• Archiv der Kategorie: Uncategorized

Starten mit WEMOS LOLIIN ESP32

Basiert auf dem Artikel „Smarte Helfer selbst gebaut“ im CT Heft Nr. 2018/2 S. 64ff.

Software-Links dazu.

Sehr guten Einstieg in den ESP32 bietet auch: https://youtu.be/xPlN_Tk3VLQ

 

Schritt 1: Arduino IDE herunter laden

Schritt 2: ESP32 SW-Ausrüstung in Arduino-IDE einspielen

Dazu ist es einfacher die Installation via „Board-Manager“ durchzuführen: Anleitung (aus der Espressive Page)

Anleitung Backup: Dazu unter Preferences ‚Additional Board Managers‘ den hier https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json eintragen (mehrere solche URL würden mit Komma separiert). Dann „Boards Manager“ aus „Tools > Board menu“ öffnen „esp32 platform“ installieren.

Schritt 3: CT Software Libraries einspielen

Vorgehen gemäss Heft. SW Links unter ct.de/y73t

Nachtrag 14.03.2021: Jedoch: Statt ‚Bootcamp‘ (SW library von CT) besser EspMQTTClient benutzen. -> Siehe unbedingt Dachfenster-Sensor mit Alarm auf dem Handy!

Stolperstein: (Nicht mehr relevant wenn  EspMQTTClient benutzt wird)
Bei ArduinoJson ist auf dem GITHub bereits die Version 6. Basecamp arbeitet aber nur mit Version 5 zusammen. Zum Glück hat der Arduino IDE Library-Manager eine ArduinoJson Version 5 verfügbar. —> Installiere von dort!
Nachtrag:  ct.de/y73t liefert die Bibliotheken auch direkt als ZIP. Da hätte man wahrscheinlich das Versionsproblem auch nicht.

Schritt 4: Sketch übertragen

CT stellt die Beispielcodes zu Verfügung. -> Z.B. Beispielcodes für Dachfenster-Sensor mit Alarm auf dem Handy (siehe dort)!

Zuerst Sketch in Editor der IDE laden.

Zu Übertragung:
– Unter ‚Tools‘ > ‚Board‘ das passende ESP Board einstellen. Unter dem ‚Board‘-Menu muss es ein ‚ESP32 Arduino‘-Menu haben, ansonsten ist wahrscheinlich Schritt 2 nicht richtig ausgeführt worden.
Wähle ‚WEMOS LOLIN32‚. Wenn der nicht geht ‚ESP32 Dev Module‚.
– Reduziere allenfalls die Übertragungsgeschwindigkeit
– Wähle den richtigen Port, nämlich jenen, der im Gerätemanager (devmgmt.msc (Windows)) unter „Anschlüsse (COM & LPT)“ die Bezeichnung „USB to UART Bridge“ trägt. Falls kein solcher vorliegt, sieh weiter unten, Stichwort ‚Übertragungsfehler‚.
– Menu ‚Sketch‘ > ‚Upload‘
– Die Meldung „Leaving…  Hard resetting via RTS pin… “ ist nicht als Fehlermeldung zu betrachten.

Bei Übertragungsfehlern (typischerweise Timout) prüfen:
– Innerhalb des Gerätemanager (devmgmt.msc (Windows)) prüfen ob unter „Anschlüsse (COM & LPT)“ ein „Silicon Labs CP210x USB to UART Bridge“ vorhanden ist. Wenn nicht, liegt das eventuell daran, dass ein Wackel vorliegt. Kabel am ESP anpressen kann schon helfen, oder aber das USB Kabel wechseln. Möglich wäre auch das Windows tatsächlich den Treiber nicht installiert hat. Man ihn also manuell nachinstallieren müsste.

 

Eclipse Plugin manuell installieren

Situation: Die Firewall blockert die Update Site von Eclipse. Man ist sich aber sicher, dass das Plugin, das man installieren möchte unbedenklich ist, z.B. weil es vom der vertrauenswürdeigen Site download.eclipse.org kommt.

Löungsansätze:

How to Download Eclipse Update Site for Offline Use

How can I download an Eclipse plugin as a zip archive using an update site?

How to install plugin for Eclipse from .zip

Eclipse: How to install a plugin manually?

 

Mocks erzeugen für via Class spezifizierte Objekte

Probleme:

Problem 1: Dynamisches Mocking:

Eine Methode soll Mocks für verschiedene Service-Klassen definieren. In der Methode selbst kann nicht jede in ihr zu Mockende Klasse separat auscodiert werden.

D.h.:

Mockito.when(MeineKlasse.meinMethode())

ist nicht möglich.

Stattdessen wird der Methode ein Class -Objekt übergeben, die den zu mockenden Service definiert.

 

Problem 2:
Wenn ein bestimmter request vorliegt muss ein definierter Reply zurück gegeben werden.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(new Bohne1("X"))).thenReturn("desired return");

Problem 3 :
Definition einer Sequenz der durch den Mock zurückzugebender Return-Werte.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(Mockito.any())).thenReturn("1").thenReturn("2").thenReturn("3");

 

Beispiel, das alles obigen Probleme löst:

HPServiceMockFactory.

import org.mockito.stubbing.OngoingStubbing;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.when;

public class HPServiceMockFactory<T> {

    public enum MockMatchingType {IN_SEQUENCE, BY_REQUEST_MATCH};

    public  <T> T prepareMock(T mock, Class bdType, String svcName, MockMatchingType mockMatchingType, Object[] parameters, Object[] desiredReturns){

        Method svc = null;
        for (Method method : bdType.getDeclaredMethods()) {
            // check if method with this name and number of arguments is declared
            if ((method.getParameterTypes().length == parameters.length) && (method.getName().equals(svcName))) {
                // check method parameters
                if (allinstanceof(parameters, method.getParameterTypes())) {
                    try {
                        Object[] paramsForInvocation = new Object[parameters.length];
                        for(int i = 0;  i < parameters.length; i++){
                            if(mockMatchingType.equals(MockMatchingType.IN_SEQUENCE)){
                                // When we want to invoke in sequence: First invocation gets desiredReturn[0], second gets desiredReturn[1], ...
                                // Then we should narrow only to anyObject parameters (or we could narrow the the suiting parameter classes)
                                paramsForInvocation[i] = anyObject();
                            }else{
                                // When we want the mock to return an answer which is defined by its request being equal as the one when the mock is called
                                // then we have to call the mock and pass the expected parameters BEFORE (farther below) define the return values (via the "thenReturn(..))
                                paramsForInvocation[i] = parameters[i];
                            }
                        }

                        svc = bdType.getDeclaredMethod(svcName, method.getParameterTypes());
                        svc.invoke(mock, paramsForInvocation);
                    } catch (NoSuchMethodException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (InvocationTargetException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (IllegalAccessException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    }
                }
            }
        }

        if (svc == null) {
            throw new IllegalStateException("Service method could not be found");
        }

        OngoingStubbing<Object> ongoingStubbing = when(svc);
        for(Object desiredReturn : desiredReturns){
            ongoingStubbing = ongoingStubbing.thenReturn(desiredReturn);
        }


        return mock;

    }
    private boolean allinstanceof(Object obj[], Class<?> classes[]) {

        for (int i = 0; i < obj.length; i++) {
            Class<?> clazz = classes[i];
            Object o = obj[i];
            if (clazz.isPrimitive()) {
                if (clazz == boolean.class) {
                    if (!(o instanceof Boolean)) {
                        return false;
                    }
                } else if (clazz == int.class) {
                    if (!(o instanceof Integer)) {
                        return false;
                    }
                }
            } else {
                if (o != null && !clazz.isInstance(o)) {
                    return false;
                }
            }
        }

        return true;
    }
}

Aufrufende Klasse:

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

import java.util.Objects;

import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.BY_REQUEST_MATCH;
import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.IN_SEQUENCE;

/**
 * Demonstrates how Mockito.when(null) can be used to tell Mockito to
 * return a given value if  objects equals to given ones are passed to the mocked method
 */
public class HPServiceMockTest {
    @Test
    public void mustReturnMockAnswersAsDefinedInASequence(){
        HPService mockedObject = Mockito.mock(HPService.class);
        Object[] parameters = new Object[1];
        parameters[0] = new Bohne1("X");
        String[] desiredReturns = {"Response 1", "Response 2", "Response 3"};
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", IN_SEQUENCE,  parameters, desiredReturns);

        Assert.assertEquals(desiredReturns[0], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[1], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[2], mockedObject.returnOnObj(new Bohne1("ANY")));
    }

    @Test
    public void mustReturnMockAnswersThatMatchTheGivenRequest(){
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        HPService mockedObject = Mockito.mock(HPService.class);

        Object[] whenReqParams1 = new Object[1];
        whenReqParams1[0] = new Bohne1("Request that must match 1");
        String[] desiredReturns1 = {"Right Response 1"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams1, desiredReturns1);

        Object[] whenReqParams2 = new Object[1];
        whenReqParams2[0] = new Bohne1("Request that must match 2");
        String[] desiredReturns2 = {"Right Response 2"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams2, desiredReturns2);

        Assert.assertEquals(desiredReturns1[0], mockedObject.returnOnObj(new Bohne1("Request that must match 1")));
        Assert.assertEquals(desiredReturns2[0], mockedObject.returnOnObj(new Bohne1("Request that must match 2")));
        Assert.assertNull(mockedObject.returnOnObj(new Bohne1("ANY")));
    }

}
class HPService {
    public String returnOnObj(Bohne1 in){return  "not mocked";}
}
class Bohne1 {
    public String id;

    public Bohne1(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Bohne1)) return false;
        Bohne1 bohne1 = (Bohne1) o;
        return Objects.equals(id, bohne1.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Dynamische Mocking

Probleme:

Problem 1: Dynamisches Mocking:

Eine Methode soll Mocks für verschiedene Service-Klassen definieren. In der Methode selbst kann nicht jede in ihr zu Mockende Klasse separat auscodiert werden.

D.h.:

Mockito.when(MeineKlasse.meinMethode())

ist nicht möglich.

Stattdessen wird der Methode ein Class -Objekt übergeben, die den zu mockenden Service definiert.

 

Problem 2:
Wenn ein bestimmter request vorliegt muss ein definierter Reply zurück gegeben werden.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(new Bohne1("X"))).thenReturn("desired return");

Problem 3 :
Definition einer Sequenz der durch den Mock zurückzugebender Return-Werte.

MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(Mockito.any())).thenReturn("1").thenReturn("2").thenReturn("3");

 

Beispiel, das alles obigen Probleme löst:

HPServiceMockFactory.class

import org.mockito.stubbing.OngoingStubbing;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.when;

public class HPServiceMockFactory<T> {

    public enum MockMatchingType {IN_SEQUENCE, BY_REQUEST_MATCH};

    public  <T> T prepareMock(T mock, Class bdType, String svcName, MockMatchingType mockMatchingType, Object[] parameters, Object[] desiredReturns){

        Method svc = null;
        for (Method method : bdType.getDeclaredMethods()) {
            // check if method with this name and number of arguments is declared
            if ((method.getParameterTypes().length == parameters.length) && (method.getName().equals(svcName))) {
                // check method parameters
                if (allinstanceof(parameters, method.getParameterTypes())) {
                    try {
                        Object[] paramsForInvocation = new Object[parameters.length];
                        for(int i = 0;  i < parameters.length; i++){
                            if(mockMatchingType.equals(MockMatchingType.IN_SEQUENCE)){
                                // When we want to invoke in sequence: First invocation gets desiredReturn[0], second gets desiredReturn[1], ...
                                // Then we should narrow only to anyObject parameters (or we could narrow the the suiting parameter classes)
                                paramsForInvocation[i] = anyObject();
                            }else{
                                // When we want the mock to return an answer which is defined by its request being equal as the one when the mock is called
                                // then we have to call the mock and pass the expected parameters BEFORE (farther below) define the return values (via the "thenReturn(..)) 
                                paramsForInvocation[i] = parameters[i];
                            }
                        }

                        svc = bdType.getDeclaredMethod(svcName, method.getParameterTypes());
                        svc.invoke(mock, paramsForInvocation);
                    } catch (NoSuchMethodException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (InvocationTargetException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    } catch (IllegalAccessException e) {
                        throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
                    }
                }
            }
        }

        if (svc == null) {
            throw new IllegalStateException("Service method could not be found");
        }

        OngoingStubbing<Object> ongoingStubbing = when(svc);
        for(Object desiredReturn : desiredReturns){
            ongoingStubbing = ongoingStubbing.thenReturn(desiredReturn);
        }


        return mock;

    }
    private boolean allinstanceof(Object obj[], Class<?> classes[]) {

        for (int i = 0; i < obj.length; i++) {
            Class<?> clazz = classes[i];
            Object o = obj[i];
            if (clazz.isPrimitive()) {
                if (clazz == boolean.class) {
                    if (!(o instanceof Boolean)) {
                        return false;
                    }
                } else if (clazz == int.class) {
                    if (!(o instanceof Integer)) {
                        return false;
                    }
                }
            } else {
                if (o != null && !clazz.isInstance(o)) {
                    return false;
                }
            }
        }

        return true;
    }
}

Test Klassen:

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

import java.util.Objects;

import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.BY_REQUEST_MATCH;
import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.IN_SEQUENCE;

/**
 * Demonstrates how Mockito.when(null) can be used to tell Mockito to
 * return a given value if  objects equals to given ones are passed to the mocked method
 */
public class HPServiceMockTest {
    @Test
    public void mustReturnMockAnswersAsDefinedInASequence(){
        HPService mockedObject = Mockito.mock(HPService.class);
        Object[] parameters = new Object[1];
        parameters[0] = new Bohne1("X");
        String[] desiredReturns = {"Response 1", "Response 2", "Response 3"};
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", IN_SEQUENCE,  parameters, desiredReturns);

        Assert.assertEquals(desiredReturns[0], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[1], mockedObject.returnOnObj(new Bohne1("ANY")));
        Assert.assertEquals(desiredReturns[2], mockedObject.returnOnObj(new Bohne1("ANY")));
    }

    @Test
    public void mustReturnMockAnswersThatMatchTheGivenRequest(){
        HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
        HPService mockedObject = Mockito.mock(HPService.class);

        Object[] whenReqParams1 = new Object[1];
        whenReqParams1[0] = new Bohne1("Request that must match 1");
        String[] desiredReturns1 = {"Right Response 1"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams1, desiredReturns1);

        Object[] whenReqParams2 = new Object[1];
        whenReqParams2[0] = new Bohne1("Request that must match 2");
        String[] desiredReturns2 = {"Right Response 2"};
        myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH,  whenReqParams2, desiredReturns2);

        Assert.assertEquals(desiredReturns1[0], mockedObject.returnOnObj(new Bohne1("Request that must match 1")));
        Assert.assertEquals(desiredReturns2[0], mockedObject.returnOnObj(new Bohne1("Request that must match 2")));
        Assert.assertNull(mockedObject.returnOnObj(new Bohne1("ANY")));
    }

}
class HPService {
    public String returnOnObj(Bohne1 in){return  "not mocked";}
}
class Bohne1 {
    public String id;

    public Bohne1(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Bohne1)) return false;
        Bohne1 bohne1 = (Bohne1) o;
        return Objects.equals(id, bohne1.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
... code ...

Mockito.when(null) – Return basierend auf equality zu gegebenem Input

Mockito.mock(null)

Weshalb sollte das sinn machen?

Mockito.when(null).thenReturn(meinObjekt)

bedeutet eigentlich: Liebes Mockito. Nimm den letzten Aufruf auf irgend einem Mock. Wenn irgendwann derselbe Aufruf mit denselben Parametern gemacht werden sollte, dann gib „meinObjekt“ zurück.

Dies wird unten demonstriert.

import org.mockito.Mockito;

import java.util.Objects;

/**
 * Demonstrates how Mockito.when(null) can be used to tell Mockito to 
 * return a given value if  objects equals to given ones are passed to the mocked method 
 */
public class HPTest {
    public static void main(String[] args) {
        MyObj mockedObject = Mockito.mock(MyObj.class);
        
        /* Tell Mockito, that if get1() is called, then return "super cool string 1.1"*/
        mockedObject.get1();
        Mockito.when(null).thenReturn("super cool string 1.1");
        mockedObject.get2();
        Mockito.when(null).thenReturn("super cool string 2");
        System.out.println(mockedObject.get1());
        System.out.println(mockedObject.get1());
        System.out.println(mockedObject.get2());
        System.out.println(mockedObject.toString());


        /* Tell Mockito, that if return1("1") is called, then return "Return 1" */
        mockedObject.return1("1");
        Mockito.when(null).thenReturn("Return 1");

        /* but if return1("2") is called, then return "Return 2" */
        mockedObject.return1("2");
        Mockito.when(null).thenReturn("Return 2");

        System.out.println(mockedObject.return1("1"));
        System.out.println(mockedObject.return1("2"));
        System.out.println(mockedObject.return1("2"));
        System.out.println(mockedObject.return1("1"));

        mockedObject.returnOnObj(new Bohne("A"));
        Mockito.when(null).thenReturn("On Obj A");

        mockedObject.returnOnObj(new Bohne("B"));
        Mockito.when(null).thenReturn("On Obj B");

        System.out.println(mockedObject.returnOnObj(new Bohne("A")));
        System.out.println(mockedObject.returnOnObj(new Bohne("B")));
        System.out.println(mockedObject.returnOnObj(new Bohne("B")));
        System.out.println(mockedObject.returnOnObj(new Bohne("A")));
    }

}
class MyObj {
    public String get1(){return "not mocked 1";}
    public String get2(){return "not mocked 2";}
    public String return1(String in){return  "not mocked";}
    public String returnOnObj(Bohne in){return  "not mocked";}
}
class Bohne {
    public String id;

    public Bohne(String id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Bohne)) return false;
        Bohne bohne = (Bohne) o;
        return Objects.equals(id, bohne.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
/*
Output:
super cool string 1.1
super cool string 1.1
super cool string 2
Mock for MyObj, hashCode: 650023597
Return 1
Return 2
Return 2
Return 1
On Obj A
On Obj B
On Obj B
On Obj A

Process finished with exit code 0
 */

 

Tomcat 8 mit HTTPS erreichtbar machen – Client Authentication via Zertifikat

A) Zertifikate erstellen

Siehe X.509 Authentication in Spring Security

B) Vorgehensweise via Tomcat-Configuration

In $CATALINA_HOME/conf/settings.xml wurde

<Connector
        protocol="org.apache.coyote.http11.Http11NioProtocol"
        port="8443" maxThreads="200"
        scheme="https" secure="true" SSLEnabled="true"
<!-- Für server auth: --> 
        keystoreFile="conf/keystore.jks" keystorePass="changeit"
<!-- Für client auth: --> 
        truststoreFile="conf/truststore.jks" truststorePass="changeit" 
        clientAuth="true" sslProtocol="TLS"/>

eingefügt.
Dies bewirkt, dass unter Port 8443 ein Zugang angeboten wird, der TLS geschlüsselt wird.
Wenn der andere Connector

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

im settings.xml drin bleibt, dass ist per se weiterhin auch die HTTP-Adresse offen.

Die Applikation (falls keine eigene darüber installiert wurde ist das die Tomcat-Welcome-Page) ist also immernoch über

http://localhost:8080 und https://localhost:8443 erreichbar.

Wird aber eine Web-App mit web.xml mit Security constraint, wie z.B. im folgenden installiert, dann wird die definierte URL immer auf HTTPS umgeleitet.

<security-constraint>

    <web-resource-collection>
        <web-resource-name>Secured</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>

    ...

    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>

</security-constraint>

–> Siehe StackOverflow-Artikel über Redirect

Obige Config setzt nicht nur HTTP und Server-Authentication auf, sondern auch Client-Authentication. Das bedeutet, dass wenn man auf https://localhost:8443 zugreifen möchte, man im Browser das Client-Certifikat installieren muss. Ruft man die Seite dann auf, wird einem eine Liste vom möglichen Zerts zur Wahl angeboten.

 

Referenzen:

 

Schließen