]> git.basschouten.com Git - openhab-addons.git/blob
be48f638bddc4fd999c3629e391ef4943fb2051d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.io.hueemulation.internal.upnp;
14
15 import static org.hamcrest.CoreMatchers.is;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.assertEquals;
18 import static org.mockito.Mockito.mock;
19
20 import java.io.IOException;
21 import java.net.DatagramPacket;
22 import java.net.DatagramSocket;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Executor;
25 import java.util.concurrent.TimeUnit;
26 import java.util.concurrent.TimeoutException;
27
28 import javax.ws.rs.client.ClientBuilder;
29
30 import org.eclipse.jetty.client.api.ContentResponse;
31 import org.glassfish.grizzly.osgi.httpservice.HttpServiceImpl;
32 import org.glassfish.grizzly.osgi.httpservice.OSGiMainHandler;
33 import org.glassfish.grizzly.osgi.httpservice.util.Logger;
34 import org.glassfish.jersey.server.ResourceConfig;
35 import org.hamcrest.CoreMatchers;
36 import org.junit.jupiter.api.AfterAll;
37 import org.junit.jupiter.api.AfterEach;
38 import org.junit.jupiter.api.BeforeAll;
39 import org.junit.jupiter.api.BeforeEach;
40 import org.junit.jupiter.api.Test;
41 import org.mockito.ArgumentMatchers;
42 import org.mockito.Mockito;
43 import org.openhab.io.hueemulation.internal.rest.CommonSetup;
44 import org.openhab.io.hueemulation.internal.rest.LightsAndGroups;
45 import org.osgi.framework.Bundle;
46 import org.osgi.util.tracker.ServiceTracker;
47
48 /**
49  * Tests the upnp server part if the description.xml is available and if the udp thread comes online
50  *
51  * @author David Graeff - Initial contribution
52  */
53 public class UpnpTests {
54     protected static CommonSetup commonSetup = null;
55     protected UpnpServer subject;
56     protected static OSGiMainHandler mainHttpHandler;
57     private static HttpServiceImpl httpServiceImpl;
58     private static String descriptionPath;
59
60     LightsAndGroups lightsAndGroups = new LightsAndGroups();
61
62     @BeforeAll
63     public static void setupHttpParts() throws IOException {
64         commonSetup = new CommonSetup(true);
65         commonSetup.start(new ResourceConfig());
66
67         descriptionPath = commonSetup.basePath.replace("/api", "/description.xml");
68
69         Logger logger = new org.glassfish.grizzly.osgi.httpservice.util.Logger(mock(ServiceTracker.class));
70
71         mainHttpHandler = new OSGiMainHandler(logger, mock(Bundle.class));
72         commonSetup.server.getServerConfiguration().addHttpHandler(mainHttpHandler, "/");
73
74         httpServiceImpl = new HttpServiceImpl(mock(Bundle.class), logger);
75     }
76
77     @BeforeEach
78     public void setup() {
79         Executor executor = mock(Executor.class);
80         Mockito.doAnswer(a -> {
81             ((Runnable) a.getArgument(0)).run();
82             return null;
83         }).when(executor).execute(ArgumentMatchers.any());
84         subject = new UpnpServer(executor);
85         subject.clientBuilder = ClientBuilder.newBuilder();
86         subject.httpService = httpServiceImpl;
87         subject.cs = commonSetup.cs;
88         subject.overwriteReadyToFalse = true;
89         subject.activate(); // don't execute handleEvent()
90         subject.overwriteReadyToFalse = false;
91     }
92
93     @AfterEach
94     public void tearDown() {
95         subject.deactivate();
96     }
97
98     @AfterAll
99     public static void tearDownHttp() throws Exception {
100         mainHttpHandler.unregisterAll();
101         commonSetup.dispose();
102     }
103
104     @Test
105     public void descriptionWithoutAddress() throws Exception {
106         ContentResponse response = commonSetup.client.newRequest(descriptionPath).send();
107         assertEquals(404, response.getStatus());
108     }
109
110     @Test
111     public void descriptionWithAddress()
112             throws InterruptedException, ExecutionException, TimeoutException, IOException {
113         HueEmulationConfigWithRuntime r = subject.createConfiguration(null);
114         r = subject.performAddressTest(r);
115         subject.applyConfiguration(r);
116         ContentResponse response = commonSetup.client.newRequest(descriptionPath).send();
117         assertEquals(200, response.getStatus());
118         String body = response.getContentAsString();
119         assertThat(body, is(subject.xmlDocWithAddress));
120
121         if (r == null) {
122             throw new IllegalStateException();
123         }
124
125         // UDP thread started?
126         r.startNow().get(5, TimeUnit.SECONDS);
127         assertThat(subject.upnpAnnouncementThreadRunning(), is(true));
128
129         // Send M-SEARCH UPNP "packet" and check if the result contains our bridge ID
130         try (DatagramSocket sendSocket = new DatagramSocket()) {
131             sendSocket.setSoTimeout(700);
132             byte[] bytes = "M-SEARCH".getBytes();
133             sendSocket.send(new DatagramPacket(bytes, bytes.length, subject.MULTI_ADDR_IPV4, UpnpServer.UPNP_PORT));
134             byte[] buffer = new byte[1000];
135             DatagramPacket p = new DatagramPacket(buffer, buffer.length);
136             sendSocket.receive(p);
137             String received = new String(buffer);
138             assertThat(received, CoreMatchers.startsWith("HTTP/1.1 200 OK"));
139             assertThat(received, CoreMatchers.containsString("hue-bridgeid: A668DC9B7172"));
140         }
141
142         r.dispose();
143         assertThat(subject.upnpAnnouncementThreadRunning(), is(false));
144     }
145
146     @Test
147     public void handEventTest() throws InterruptedException, ExecutionException, TimeoutException {
148         subject.handleEvent(null);
149         subject.configChangeFuture.get(5, TimeUnit.SECONDS);
150         assertThat(subject.upnpAnnouncementThreadRunning(), is(true));
151
152         subject.deactivate();
153         assertThat(subject.upnpAnnouncementThreadRunning(), is(false));
154     }
155 }