View Javadoc
1   /*
2    * Copyright (C) 2013 4th Line GmbH, Switzerland
3    *
4    * The contents of this file are subject to the terms of either the GNU
5    * Lesser General Public License Version 2 or later ("LGPL") or the
6    * Common Development and Distribution License Version 1 or later
7    * ("CDDL") (collectively, the "License"). You may not use this file
8    * except in compliance with the License. See LICENSE.txt for more
9    * information.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   */
15  
16  package org.fourthline.cling.test.control;
17  
18  import org.fourthline.cling.controlpoint.ActionCallback;
19  import org.fourthline.cling.mock.MockRouter;
20  import org.fourthline.cling.mock.MockUpnpService;
21  import org.fourthline.cling.model.action.ActionInvocation;
22  import org.fourthline.cling.model.message.StreamRequestMessage;
23  import org.fourthline.cling.model.message.StreamResponseMessage;
24  import org.fourthline.cling.model.message.UpnpHeaders;
25  import org.fourthline.cling.model.message.UpnpResponse;
26  import org.fourthline.cling.model.message.header.ContentTypeHeader;
27  import org.fourthline.cling.model.message.header.SoapActionHeader;
28  import org.fourthline.cling.model.message.header.UpnpHeader;
29  import org.fourthline.cling.model.meta.Action;
30  import org.fourthline.cling.model.meta.ActionArgument;
31  import org.fourthline.cling.model.meta.DeviceDetails;
32  import org.fourthline.cling.model.meta.LocalDevice;
33  import org.fourthline.cling.model.meta.LocalService;
34  import org.fourthline.cling.model.meta.RemoteDevice;
35  import org.fourthline.cling.model.meta.RemoteService;
36  import org.fourthline.cling.model.meta.Service;
37  import org.fourthline.cling.model.meta.StateVariable;
38  import org.fourthline.cling.model.meta.StateVariableEventDetails;
39  import org.fourthline.cling.model.meta.StateVariableTypeDetails;
40  import org.fourthline.cling.model.profile.ClientInfo;
41  import org.fourthline.cling.model.types.Datatype;
42  import org.fourthline.cling.model.types.ErrorCode;
43  import org.fourthline.cling.model.types.UDADeviceType;
44  import org.fourthline.cling.model.types.UDAServiceId;
45  import org.fourthline.cling.model.types.UDAServiceType;
46  import org.fourthline.cling.model.types.UnsignedIntegerFourBytes;
47  import org.fourthline.cling.test.data.SampleData;
48  import org.fourthline.cling.test.data.SampleServiceOne;
49  import org.fourthline.cling.transport.RouterException;
50  import org.testng.annotations.Test;
51  
52  import java.net.URI;
53  import java.util.Arrays;
54  
55  import static org.testng.Assert.assertEquals;
56  
57  
58  public class ActionInvokeOutgoingTest {
59  
60      public static final String RESPONSE_SUCCESSFUL = "<?xml version=\"1.0\"?>\n" +
61          " <s:Envelope\n" +
62          "     xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
63          "     s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
64          "   <s:Body>\n" +
65          "     <u:GetTargetResponse xmlns:u=\"urn:schemas-upnp-org:service:SwitchPower:1\">\n" +
66          "       <RetTargetValue>0</RetTargetValue>\n" +
67          "     </u:GetTargetResponse>\n" +
68          "   </s:Body>\n" +
69          " </s:Envelope>";
70  
71      public static final String RESPONSE_QUERY_VARIABLE = "<?xml version=\"1.0\"?>\n" +
72          " <s:Envelope\n" +
73          "     xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
74          "     s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
75          "   <s:Body>\n" +
76          "     <u:QueryStateVariableResponse xmlns:u=\"urn:schemas-upnp-org:control-1-0\">\n" +
77          "       <return>0</return>\n" +
78          "     </u:QueryStateVariableResponse>\n" +
79          "   </s:Body>\n" +
80          " </s:Envelope>";
81  
82      public static final String RESPONSE_FAILURE = "<?xml version=\"1.0\"?>\n" +
83          " <s:Envelope\n" +
84          "     xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
85          "     s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
86          "   <s:Body>\n" +
87          "     <s:Fault>\n" +
88          "       <faultcode>s:Client</faultcode>\n" +
89          "       <faultstring>UPnPError</faultstring>\n" +
90          "       <detail>\n" +
91          "         <UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n" +
92          "           <errorCode>611</errorCode>\n" +
93          "           <errorDescription>A test string</errorDescription>\n" +
94          "         </UPnPError>\n" +
95          "       </detail>\n" +
96          "     </s:Fault>\n" +
97          "   </s:Body>\n" +
98          " </s:Envelope>";
99  
100     public static final String RESPONSE_NEGATIVE_VALUE = "<?xml version=\"1.0\"?>\n" +
101         " <s:Envelope\n" +
102         "     xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
103         "     s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
104         "   <s:Body>\n" +
105         "     <u:GetNegativeValueResponse xmlns:u=\"urn:schemas-upnp-org:service:MyService:1\">\n" +
106         "       <Result>-1</Result>\n" + // That's an illegal value for this state var!
107         "     </u:GetNegativeValueResponse>\n" +
108         "   </s:Body>\n" +
109         " </s:Envelope>";
110 
111     @Test
112     public void callLocalGet() throws Exception {
113 
114         // Registery local device and its service
115         MockUpnpService upnpService = new MockUpnpService();
116         LocalDevice ld = ActionSampleData.createTestDevice();
117         LocalService service = ld.getServices()[0];
118         upnpService.getRegistry().addDevice(ld);
119 
120         Action action = service.getAction("GetTarget");
121         ActionInvocation actionInvocation = new ActionInvocation(action);
122 
123         final boolean[] assertions = new boolean[1];
124         ActionCallback callback = new ActionCallback(actionInvocation) {
125             @Override
126             public void success(ActionInvocation invocation) {
127                 assertions[0] = true;
128             }
129 
130             @Override
131             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
132                 assertions[0] = false;
133             }
134 
135         };
136 
137         upnpService.getControlPoint().execute(callback);
138 
139         assert actionInvocation.getFailure() == null;
140         assertEquals(upnpService.getRouter().getSentStreamRequestMessages().size(), 0);
141         assertEquals(assertions[0], true);
142         assertEquals(actionInvocation.getOutput().length, 1);
143         assertEquals(actionInvocation.getOutput()[0].toString(), "0");
144 
145     }
146 
147 
148     @Test
149     public void callLocalWrongAction() throws Exception {
150 
151         // Registery local device and its service
152         MockUpnpService upnpService = new MockUpnpService();
153         LocalDevice ld = ActionSampleData.createTestDevice();
154         LocalService service = ld.getServices()[0];
155         upnpService.getRegistry().addDevice(ld);
156 
157         assertEquals(service.getAction("NonExistentAction"), null);
158     }
159 
160     @Test
161     public void callLocalSetException() throws Exception {
162 
163         // Registery local device and its service
164         MockUpnpService upnpService = new MockUpnpService();
165         LocalDevice ld = ActionSampleData.createTestDevice(ActionSampleData.LocalTestServiceThrowsException.class);
166         LocalService service = ld.getServices()[0];
167         upnpService.getRegistry().addDevice(ld);
168 
169         Action action = service.getAction("SetTarget");
170         ActionInvocation actionInvocation = new ActionInvocation(action);
171 
172         actionInvocation.setInput("NewTargetValue", true);
173 
174         final boolean[] assertions = new boolean[1];
175         ActionCallback callback = new ActionCallback(actionInvocation) {
176             @Override
177             public void success(ActionInvocation invocation) {
178                 assertions[0] = false;
179             }
180 
181             @Override
182             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
183                 assert operation == null; // Local calls don't have an operation
184                 assertions[0] = true;
185             }
186         };
187 
188         upnpService.getControlPoint().execute(callback);
189 
190         assert actionInvocation.getFailure() != null;
191         assertEquals(upnpService.getRouter().getSentStreamRequestMessages().size(), 0);
192         assertEquals(assertions[0], true);
193 
194         assertEquals(actionInvocation.getFailure().getErrorCode(), ErrorCode.ACTION_FAILED.getCode());
195         assertEquals(
196             actionInvocation.getFailure().getMessage(),
197             ErrorCode.ACTION_FAILED.getDescription() + ". Something is wrong."
198         );
199     }
200 
201     @Test
202     public void callRemoteGet() throws Exception {
203 
204         MockUpnpService upnpService = new MockUpnpService() {
205             @Override
206             protected MockRouter createRouter() {
207                 return new MockRouter(getConfiguration(), getProtocolFactory()) {
208 
209                     @Override
210                     public StreamResponseMessage send(StreamRequestMessage msg) throws RouterException {
211                         return super.send(msg);
212                     }
213 
214                     @Override
215                     public StreamResponseMessage[] getStreamResponseMessages() {
216                         return new StreamResponseMessage[]{
217                             new StreamResponseMessage(RESPONSE_SUCCESSFUL)
218                         };
219                     }
220                 };
221             }
222         };
223 
224         // Register remote device and its service
225         RemoteDevice device = SampleData.createRemoteDevice();
226         Service service = SampleData.getFirstService(device);
227         upnpService.getRegistry().addDevice(device);
228 
229         Action action = service.getAction("GetTarget");
230 
231         UpnpHeaders extraHeaders = new UpnpHeaders();
232         extraHeaders.add(UpnpHeader.Type.USER_AGENT.getHttpName(), "MyCustom/Agent");
233         extraHeaders.add("X-Custom-Header", "foo");
234 
235         ActionInvocation actionInvocation =
236             new ActionInvocation(
237                 action,
238                 new ClientInfo(extraHeaders)
239             );
240 
241         final boolean[] assertions = new boolean[1];
242         ActionCallback callback = new ActionCallback(actionInvocation) {
243             @Override
244             public void success(ActionInvocation invocation) {
245                 assertions[0] = true;
246             }
247 
248             @Override
249             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
250                 assertions[0] = false;
251             }
252         };
253 
254         upnpService.getControlPoint().execute(callback);
255 
256         assert actionInvocation.getFailure() == null;
257         assertEquals(upnpService.getRouter().getSentStreamRequestMessages().size(), 1);
258         assertEquals(assertions[0], true);
259 
260         StreamRequestMessage request = upnpService.getRouter().getSentStreamRequestMessages().get(0);
261 
262         // Mandatory headers
263         assertEquals(
264             request.getHeaders().getFirstHeaderString(UpnpHeader.Type.CONTENT_TYPE),
265             ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8.toString()
266         );
267         assertEquals(
268             request.getHeaders().getFirstHeaderString(UpnpHeader.Type.SOAPACTION),
269             "\"" + SampleServiceOne.getThisServiceType().toString() + "#GetTarget\""
270         );
271 
272         // The extra headers
273         assertEquals(
274             request.getHeaders().getFirstHeaderString(UpnpHeader.Type.USER_AGENT),
275             "MyCustom/Agent"
276         );
277         assertEquals(
278             request.getHeaders().getFirstHeader("X-CUSTOM-HEADER"),
279             "foo"
280         );
281 
282         assertEquals(actionInvocation.getOutput().length, 1);
283         assertEquals(actionInvocation.getOutput()[0].toString(), "0");
284 
285     }
286 
287     @Test
288     public void callRemoteGetFailure() throws Exception {
289 
290         MockUpnpService upnpService = new MockUpnpService() {
291             @Override
292             protected MockRouter createRouter() {
293                 return new MockRouter(getConfiguration(), getProtocolFactory()) {
294                     @Override
295                     public StreamResponseMessage[] getStreamResponseMessages() {
296                         return new StreamResponseMessage[]{
297                             new StreamResponseMessage(new UpnpResponse(UpnpResponse.Status.INTERNAL_SERVER_ERROR), RESPONSE_FAILURE)
298                         };
299                     }
300                 };
301             }
302         };
303 
304         // Registery remote device and its service
305         RemoteDevice device = SampleData.createRemoteDevice();
306         Service service = SampleData.getFirstService(device);
307         upnpService.getRegistry().addDevice(device);
308 
309         Action action = service.getAction("GetTarget");
310 
311         ActionInvocation actionInvocation = new ActionInvocation(action);
312         final boolean[] assertions = new boolean[1];
313         ActionCallback callback = new ActionCallback(actionInvocation) {
314             @Override
315             public void success(ActionInvocation invocation) {
316                 assertions[0] = false;
317             }
318 
319             @Override
320             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
321                 assertEquals(operation.getStatusCode(), UpnpResponse.Status.INTERNAL_SERVER_ERROR.getStatusCode());
322                 assertions[0] = true;
323             }
324         };
325 
326         upnpService.getControlPoint().execute(callback);
327 
328         assert actionInvocation.getFailure() != null;
329         assertEquals(upnpService.getRouter().getSentStreamRequestMessages().size(), 1);
330         assertEquals(assertions[0], true);
331         assertEquals(actionInvocation.getFailure().getErrorCode(), ErrorCode.INVALID_CONTROL_URL.getCode());
332         assertEquals(
333             actionInvocation.getFailure().getMessage(),
334             "A test string"
335         );
336 
337     }
338 
339     @Test
340     public void callRemoteGetNotFoundFailure() throws Exception {
341 
342         MockUpnpService upnpService = new MockUpnpService() {
343             @Override
344             protected MockRouter createRouter() {
345                 return new MockRouter(getConfiguration(), getProtocolFactory()) {
346                     @Override
347                     public StreamResponseMessage[] getStreamResponseMessages() {
348                         return new StreamResponseMessage[]{
349                             new StreamResponseMessage(new UpnpResponse(UpnpResponse.Status.NOT_FOUND))
350                         };
351                     }
352                 };
353             }
354         };
355 
356         // Registery remote device and its service
357         RemoteDevice device = SampleData.createRemoteDevice();
358         Service service = SampleData.getFirstService(device);
359         upnpService.getRegistry().addDevice(device);
360 
361         Action action = service.getAction("GetTarget");
362 
363         ActionInvocation actionInvocation = new ActionInvocation(action);
364         final boolean[] assertions = new boolean[1];
365         ActionCallback callback = new ActionCallback(actionInvocation) {
366             @Override
367             public void success(ActionInvocation invocation) {
368                 assertions[0] = false;
369             }
370 
371             @Override
372             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
373                 assertEquals(operation.getStatusCode(), UpnpResponse.Status.NOT_FOUND.getStatusCode());
374                 assertions[0] = true;
375             }
376         };
377 
378         upnpService.getControlPoint().execute(callback);
379 
380         assert actionInvocation.getFailure() != null;
381         assertEquals(upnpService.getRouter().getSentStreamRequestMessages().size(), 1);
382         assertEquals(assertions[0], true);
383         assertEquals(actionInvocation.getFailure().getErrorCode(), ErrorCode.ACTION_FAILED.getCode());
384         assertEquals(
385             actionInvocation.getFailure().getMessage(),
386             ErrorCode.ACTION_FAILED.getDescription() + ". Non-recoverable remote execution failure: 404 Not Found."
387         );
388 
389     }
390 
391     @Test
392     public void callRemoteGetNoResponse() throws Exception {
393 
394         MockUpnpService upnpService = new MockUpnpService();
395 
396         // Registery remote device and its service
397         RemoteDevice device = SampleData.createRemoteDevice();
398         Service service = SampleData.getFirstService(device);
399         upnpService.getRegistry().addDevice(device);
400 
401         Action action = service.getAction("GetTarget");
402 
403         ActionInvocation actionInvocation = new ActionInvocation(action);
404         final boolean[] assertions = new boolean[1];
405         ActionCallback callback = new ActionCallback(actionInvocation) {
406             @Override
407             public void success(ActionInvocation invocation) {
408                 assertions[0] = false;
409             }
410 
411             @Override
412             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
413                 assert operation == null;
414                 assertions[0] = true;
415             }
416         };
417 
418         upnpService.getControlPoint().execute(callback);
419 
420         assert actionInvocation.getFailure() != null;
421         assertEquals(upnpService.getRouter().getSentStreamRequestMessages().size(), 1);
422         assertEquals(assertions[0], true);
423         assertEquals(actionInvocation.getFailure().getErrorCode(), ErrorCode.ACTION_FAILED.getCode());
424         assertEquals(
425             actionInvocation.getFailure().getMessage(),
426             ErrorCode.ACTION_FAILED.getDescription() + ". Connection error or no response received."
427         );
428     }
429 
430     @Test
431     public void callRemoteNegativeValue() throws Exception {
432 
433         MockUpnpService upnpService = new MockUpnpService() {
434             @Override
435             protected MockRouter createRouter() {
436                 return new MockRouter(getConfiguration(), getProtocolFactory()) {
437                     @Override
438                     public StreamResponseMessage[] getStreamResponseMessages() {
439                         return new StreamResponseMessage[]{
440                             new StreamResponseMessage(RESPONSE_NEGATIVE_VALUE)
441                         };
442                     }
443                 };
444             }
445         };
446 
447         // Registery remote device and its service
448         RemoteDevice device = new RemoteDevice(
449             SampleData.createRemoteDeviceIdentity(),
450             new UDADeviceType("MyDevice"),
451             new DeviceDetails("JustATest"),
452             new RemoteService(
453                 new UDAServiceType("MyService"),
454                 new UDAServiceId("MyService"),
455                 URI.create("/scpd.xml"),
456                 URI.create("/control"),
457                 URI.create("/events"),
458                 new Action[]{
459                     new Action(
460                         "GetNegativeValue",
461                         new ActionArgument[]{
462                             new ActionArgument("Result", "NegativeValue", ActionArgument.Direction.OUT)
463                         }
464                     )
465                 },
466                 new StateVariable[]{
467                     new StateVariable(
468                         "NegativeValue",
469                         new StateVariableTypeDetails(Datatype.Builtin.UI4.getDatatype()),
470                         new StateVariableEventDetails(false)
471                     )
472                 }
473             )
474         );
475 
476         upnpService.getRegistry().addDevice(device);
477 
478         Action action = device.getServices()[0].getAction("GetNegativeValue");
479 
480         ActionInvocation actionInvocation = new ActionInvocation(action);
481         final boolean[] assertions = new boolean[1];
482         ActionCallback callback = new ActionCallback(actionInvocation) {
483             @Override
484             public void success(ActionInvocation invocation) {
485                 assertions[0] = true;
486             }
487 
488             @Override
489             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
490                 assertions[0] = false;
491             }
492         };
493 
494         upnpService.getControlPoint().execute(callback);
495 
496         assert actionInvocation.getFailure() == null;
497         // The illegal "-1" value should have been converted (with warning) to 0
498         assertEquals(actionInvocation.getOutput("Result").getValue(), new UnsignedIntegerFourBytes(0));
499     }
500 
501     /* TODO: M-POST support
502     @Test
503     public void callRemoteGetMethodNotSupported() throws Exception {
504 
505 
506         MockUpnpService upnpService = new MockUpnpService() {
507             @Override
508             public StreamResponseMessage getStreamResponseMessage(StreamRequestMessage msg) {
509                 if (msg.getOperation().getMethod().equals(UpnpRequest.Method.POST)) {
510                     return new StreamResponseMessage(new UpnpResponse(UpnpResponse.Status.METHOD_NOT_SUPPORTED));
511                 } else if (msg.getOperation().getMethod().equals(UpnpRequest.Method.MPOST)) {
512                     return new StreamResponseMessage(RESPONSE_SUCCESSFUL);
513                 } else {
514                     throw new RuntimeException("Received unknown msg: " + msg);
515                 }
516 
517             }
518         };
519 
520         // Registery remote device and its service
521         RemoteDevice device = SampleData.createRemoteDevice();
522         Service service = SampleData.getFirstService(device);
523         upnpService.getRegistry().addDevice(device);
524 
525         Action action = service.getAction("GetTarget");
526 
527         ActionInvocation actionInvocation = new ActionInvocation(action);
528         final boolean[] assertions = new boolean[1];
529         ActionCallback callback = new ActionCallback(actionInvocation) {
530             public void failure(ActionInvocation invocation, UpnpResponse operation) {
531                 assertions[0] = false;
532             }
533 
534             public void success(ActionInvocation invocation) {
535                 assertions[0] = true;
536             }
537         };
538 
539         upnpService.getControlPoint().execute(callback);
540 
541         assertEquals(upnpService.getSentStreamRequestMessages().size(), 2);
542         assertEquals(assertions[0], true);
543 
544         assertEquals(upnpService.getSentStreamRequestMessages().get(0).getOperation().getMethod(), UpnpRequest.Method.POST);
545         assertEquals(upnpService.getSentStreamRequestMessages().get(0).getHeaders().getPrefix(UpnpHeader.Type.SOAPACTION), null);
546         assertEquals(
547                 upnpService.getSentStreamRequestMessages().get(0).getHeaders().getFirstHeader(UpnpHeader.Type.CONTENT_TYPE, ContentTypeHeader.class).getString(),
548                 ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8.toString()
549         );
550 
551 
552         assertEquals(upnpService.getSentStreamRequestMessages().get(1).getOperation().getMethod(), UpnpRequest.Method.MPOST);
553         MANHeader manHeader = upnpService.getSentStreamRequestMessages().get(1).getHeaders().getFirstHeader(UpnpHeader.Type.MAN, MANHeader.class);
554         assert manHeader != null;
555         assertEquals(upnpService.getSentStreamRequestMessages().get(1).getHeaders().getPrefix(UpnpHeader.Type.SOAPACTION), manHeader.getNamespace());
556         assertEquals(
557                 upnpService.getSentStreamRequestMessages().get(1).getHeaders().getFirstHeader(UpnpHeader.Type.CONTENT_TYPE, ContentTypeHeader.class).getString(),
558                 ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8.toString()
559         );
560 
561         assert actionInvocation.getFailure() == null;
562         assertEquals(actionInvocation.getOutput().length, 1);
563         assertEquals(actionInvocation.getOutput()[0].toString(), "0");
564 
565     }
566 
567     @Test
568     public void callRemoteGetDoubleMethodNotSupported() throws Exception {
569 
570         MockUpnpService upnpService = new MockUpnpService() {
571             @Override
572             public StreamResponseMessage[] getStreamResponseMessages() {
573                 return new StreamResponseMessage[] {
574                     new StreamResponseMessage(new UpnpResponse(UpnpResponse.Status.METHOD_NOT_SUPPORTED)),
575                     new StreamResponseMessage(new UpnpResponse(UpnpResponse.Status.METHOD_NOT_SUPPORTED))
576                 };
577             }
578         };
579 
580         // Registery remote device and its service
581         RemoteDevice device = SampleData.createRemoteDevice();
582         Service service = SampleData.getFirstService(device);
583         upnpService.getRegistry().addDevice(device);
584 
585         Action action = service.getAction("GetTarget");
586 
587         ActionInvocation actionInvocation = new ActionInvocation(action);
588         final boolean[] assertions = new boolean[1];
589         ActionCallback callback = new ActionCallback(actionInvocation) {
590             public void failure(ActionInvocation invocation, UpnpResponse operation) {
591                 assertEquals(operation.getStatusCode(), UpnpResponse.Status.METHOD_NOT_SUPPORTED.getStatusCode());
592                 assertions[0] = true;
593             }
594 
595             public void success(ActionInvocation invocation) {
596                 assertions[0] = false;
597             }
598         };
599 
600         upnpService.getControlPoint().execute(callback);
601 
602         assertEquals(upnpService.getSentStreamRequestMessages().size(), 2);
603         assertEquals(assertions[0], true);
604 
605         assertEquals(upnpService.getSentStreamRequestMessages().get(0).getOperation().getMethod(), UpnpRequest.Method.POST);
606         assertEquals(upnpService.getSentStreamRequestMessages().get(0).getHeaders().getPrefix(UpnpHeader.Type.SOAPACTION), null);
607         assertEquals(
608                 upnpService.getSentStreamRequestMessages().get(0).getHeaders().getFirstHeader(UpnpHeader.Type.CONTENT_TYPE, ContentTypeHeader.class).getString(),
609                 ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8.toString()
610         );
611 
612 
613         assertEquals(upnpService.getSentStreamRequestMessages().get(1).getOperation().getMethod(), UpnpRequest.Method.MPOST);
614         MANHeader manHeader = upnpService.getSentStreamRequestMessages().get(1).getHeaders().getFirstHeader(UpnpHeader.Type.MAN, MANHeader.class);
615         assert manHeader != null;
616         assertEquals(upnpService.getSentStreamRequestMessages().get(1).getHeaders().getPrefix(UpnpHeader.Type.SOAPACTION), manHeader.getNamespace());
617         assertEquals(
618                 upnpService.getSentStreamRequestMessages().get(1).getHeaders().getFirstHeader(UpnpHeader.Type.CONTENT_TYPE, ContentTypeHeader.class).getString(),
619                 ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8.toString()
620         );
621 
622         assert actionInvocation.getFailure() != null;
623         assertEquals(actionInvocation.getFailure().getErrorCode(), ErrorCode.ACTION_FAILED.getCode());
624         assertEquals(
625                 actionInvocation.getFailure().getMessage(),
626                 ErrorCode.ACTION_FAILED.getDescription() + ". Second request (with MPOST) also failed, received Method Not Allowed again."
627         );
628     }
629     */
630 
631     @Test
632     public void callRemoteQueryStateVariable() throws Exception {
633 
634         MockUpnpService upnpService = new MockUpnpService() {
635             @Override
636             protected MockRouter createRouter() {
637                 return new MockRouter(getConfiguration(), getProtocolFactory()) {
638                     @Override
639                     public StreamResponseMessage[] getStreamResponseMessages() {
640                         return new StreamResponseMessage[]{
641                             new StreamResponseMessage(RESPONSE_QUERY_VARIABLE)
642                         };
643                     }
644                 };
645             }
646         };
647 
648         // Registery remote device and its service
649         RemoteDevice device = SampleData.createRemoteDevice();
650         Service service = SampleData.getFirstService(device);
651         upnpService.getRegistry().addDevice(device);
652 
653         Action action = service.getQueryStateVariableAction();
654         ActionInvocation actionInvocation = new ActionInvocation(action);
655         actionInvocation.setInput("varName", "Target");
656 
657         final boolean[] assertions = new boolean[1];
658         ActionCallback callback = new ActionCallback(actionInvocation) {
659             @Override
660             public void success(ActionInvocation invocation) {
661                 assertions[0] = true;
662             }
663 
664             @Override
665             public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMsg) {
666                 assertions[0] = false;
667             }
668         };
669 
670         upnpService.getControlPoint().execute(callback);
671 
672         assert actionInvocation.getFailure() == null;
673         assertEquals(upnpService.getRouter().getSentStreamRequestMessages().size(), 1);
674         assertEquals(assertions[0], true);
675         assertEquals(
676             upnpService.getRouter().getSentStreamRequestMessages().get(0).getHeaders().getFirstHeader(UpnpHeader.Type.CONTENT_TYPE, ContentTypeHeader.class).getString(),
677             ContentTypeHeader.DEFAULT_CONTENT_TYPE_UTF8.toString()
678         );
679         assertEquals(
680             upnpService.getRouter().getSentStreamRequestMessages().get(0).getHeaders().getFirstHeader(UpnpHeader.Type.SOAPACTION, SoapActionHeader.class).getString(),
681             "\"urn:schemas-upnp-org:control-1-0#QueryStateVariable\""
682         );
683         assertEquals(actionInvocation.getOutput().length, 1);
684         assertEquals(actionInvocation.getOutput()[0].getArgument().getName(), "return");
685         assertEquals(actionInvocation.getOutput()[0].toString(), "0");
686     }
687 
688 
689 }