1+ package engineer .nightowl .sonos .api .resource ;
2+
3+ import com .fasterxml .jackson .databind .ObjectMapper ;
4+ import engineer .nightowl .sonos .api .SonosApiClient ;
5+ import engineer .nightowl .sonos .api .SonosApiConfiguration ;
6+ import engineer .nightowl .sonos .api .domain .SonosHomeTheaterOptions ;
7+ import engineer .nightowl .sonos .api .enums .SonosErrorCode ;
8+ import engineer .nightowl .sonos .api .enums .SonosType ;
9+ import engineer .nightowl .sonos .api .exception .SonosApiClientException ;
10+ import engineer .nightowl .sonos .api .exception .SonosApiError ;
11+ import org .apache .http .HttpEntity ;
12+ import org .apache .http .ProtocolVersion ;
13+ import org .apache .http .StatusLine ;
14+ import org .apache .http .client .methods .CloseableHttpResponse ;
15+ import org .apache .http .client .methods .HttpGet ;
16+ import org .apache .http .entity .ContentType ;
17+ import org .apache .http .entity .StringEntity ;
18+ import org .apache .http .impl .client .CloseableHttpClient ;
19+ import org .apache .http .message .BasicHeader ;
20+ import org .apache .http .message .BasicStatusLine ;
21+ import org .junit .Assert ;
22+ import org .junit .BeforeClass ;
23+ import org .junit .Rule ;
24+ import org .junit .Test ;
25+ import org .mockito .junit .MockitoJUnit ;
26+ import org .mockito .junit .MockitoRule ;
27+ import org .mockito .quality .Strictness ;
28+
29+ import java .io .IOException ;
30+
31+ import static org .mockito .ArgumentMatchers .any ;
32+ import static org .mockito .Mockito .mock ;
33+ import static org .mockito .Mockito .when ;
34+
35+ public class BaseResourceTest
36+ {
37+ @ Rule
38+ public MockitoRule rule = MockitoJUnit .rule ().strictness (Strictness .STRICT_STUBS );
39+
40+ private static BaseResource baseResource ;
41+ private static SonosApiClient client ;
42+ private static SonosApiConfiguration configuration ;
43+ private static CloseableHttpClient mockedClient ;
44+
45+ @ BeforeClass
46+ public static void setUp () throws Exception
47+ {
48+ client = mock (SonosApiClient .class );
49+ configuration = mock (SonosApiConfiguration .class );
50+ mockedClient = mock (CloseableHttpClient .class );
51+ baseResource = new BaseResource (client );
52+
53+ when (client .getConfiguration ()).thenReturn (configuration );
54+ when (client .getHttpClient ()).thenReturn (mockedClient );
55+ when (configuration .getControlBaseUrl ()).thenReturn ("/control/api" );
56+ }
57+
58+ @ Test
59+ public void getTypeFromHeader () throws SonosApiClientException
60+ {
61+ final CloseableHttpResponse response = mock (CloseableHttpResponse .class );
62+ when (response .getFirstHeader (BaseResource .SONOS_TYPE_HEADER ))
63+ .thenReturn (new BasicHeader (BaseResource .SONOS_TYPE_HEADER , "homeTheaterOptions" ));
64+ final SonosType type = baseResource .getTypeFromHeader (response );
65+
66+ Assert .assertEquals (SonosType .homeTheaterOptions , type );
67+ }
68+
69+ @ Test
70+ public void getInvalidTypeFromHeader () throws SonosApiClientException
71+ {
72+ final CloseableHttpResponse response = mock (CloseableHttpResponse .class );
73+ when (response .getFirstHeader (BaseResource .SONOS_TYPE_HEADER ))
74+ .thenReturn (new BasicHeader (BaseResource .SONOS_TYPE_HEADER , "unexpectedValue" ));
75+
76+ try
77+ {
78+ baseResource .getTypeFromHeader (response );
79+ Assert .fail ("Did not fail as expected" );
80+ }
81+ catch (SonosApiClientException sace )
82+ {
83+ Assert .assertEquals (IllegalArgumentException .class , sace .getCause ().getClass ());
84+ }
85+ }
86+
87+ @ Test
88+ public void testThatMainApiCallWorks () throws IOException , SonosApiClientException , SonosApiError
89+ {
90+ // Test data
91+ final SonosHomeTheaterOptions options = new SonosHomeTheaterOptions ();
92+ options .setNightMode (true );
93+ options .setEnhanceDialog (true );
94+ options .setGroupingLatency (50 );
95+
96+ // Mocks
97+ final HttpGet req = baseResource .getGetRequest ("token123" , "some/test" );
98+ final HttpEntity entity = new StringEntity (new ObjectMapper ().writeValueAsString (options ), ContentType .APPLICATION_JSON );
99+
100+ final CloseableHttpResponse mockedResponse = mock (CloseableHttpResponse .class );
101+ when (mockedResponse .getEntity ()).thenReturn (entity );
102+ final StatusLine sl = new BasicStatusLine (new ProtocolVersion ("HTTP" , 1 , 1 ), 200 , null );
103+ when (mockedResponse .getStatusLine ()).thenReturn (sl );
104+ when (client .getHttpClient ().execute (any ())).thenReturn (mockedResponse );
105+ final SonosHomeTheaterOptions responseOptions = baseResource .getFromApi (SonosHomeTheaterOptions .class ,
106+ "token123" , "some/test" );
107+
108+ Assert .assertEquals (options , responseOptions );
109+ }
110+
111+ @ Test
112+ public void testSonosNotDeclaringTypeStillWorks () throws IOException , SonosApiClientException , SonosApiError
113+ {
114+ // Test data
115+ final SonosHomeTheaterOptions options = new SonosHomeTheaterOptions ();
116+ options .setNightMode (true );
117+ options .setEnhanceDialog (true );
118+ options .setGroupingLatency (50 );
119+
120+ // Mocks
121+ final HttpGet req = baseResource .getGetRequest ("token123" , "some/test" );
122+ final HttpEntity entity = new StringEntity (new ObjectMapper ().writeValueAsString (options ), ContentType .APPLICATION_JSON );
123+
124+ final CloseableHttpResponse mockedResponse = mock (CloseableHttpResponse .class );
125+ when (mockedResponse .getEntity ()).thenReturn (entity );
126+ final StatusLine sl = new BasicStatusLine (new ProtocolVersion ("HTTP" , 1 , 1 ), 200 , null );
127+ when (mockedResponse .getStatusLine ()).thenReturn (sl );
128+ when (mockedResponse .getFirstHeader (BaseResource .SONOS_TYPE_HEADER ))
129+ .thenReturn (null );
130+ when (client .getHttpClient ().execute (any ())).thenReturn (mockedResponse );
131+ final SonosHomeTheaterOptions responseOptions = baseResource .getFromApi (SonosHomeTheaterOptions .class ,
132+ "token123" , "some/test" );
133+
134+ Assert .assertEquals (options , responseOptions );
135+ }
136+
137+ @ Test
138+ public void testAuthErrorThrown () throws IOException , SonosApiClientException , SonosApiError
139+ {
140+ // Mocks
141+ final HttpGet req = baseResource .getGetRequest ("token123" , "some/test" );
142+
143+ final CloseableHttpResponse mockedResponse = mock (CloseableHttpResponse .class );
144+ final StatusLine sl = new BasicStatusLine (new ProtocolVersion ("HTTP" , 1 , 1 ), 401 , null );
145+ when (mockedResponse .getStatusLine ()).thenReturn (sl );
146+ when (client .getHttpClient ().execute (any ())).thenReturn (mockedResponse );
147+ try
148+ {
149+ baseResource .getFromApi (SonosHomeTheaterOptions .class , "token123" , "some/test" );
150+ Assert .fail ("Did not handle error response correctly" );
151+ }
152+ catch (final SonosApiClientException e )
153+ {
154+ Assert .assertEquals ("Invalid token" , e .getMessage ());
155+ }
156+ }
157+
158+ @ Test
159+ public void testApiErrorHandledCorrectly () throws IOException , SonosApiClientException , SonosApiError
160+ {
161+ // Test data
162+ final SonosApiError error = new SonosApiError ();
163+ error .setErrorCode (SonosErrorCode .ERROR_NOT_CAPABLE );
164+ error .setReason ("Some test information" );
165+
166+ // Mocks
167+ final HttpGet req = baseResource .getGetRequest ("token123" , "some/test" );
168+ final HttpEntity entity = new StringEntity (new ObjectMapper ().writeValueAsString (error ), ContentType .APPLICATION_JSON );
169+
170+ final CloseableHttpResponse mockedResponse = mock (CloseableHttpResponse .class );
171+ when (mockedResponse .getEntity ()).thenReturn (entity );
172+ final StatusLine sl = new BasicStatusLine (new ProtocolVersion ("HTTP" , 1 , 1 ), 500 , null );
173+ when (mockedResponse .getStatusLine ()).thenReturn (sl );
174+ when (mockedResponse .getFirstHeader (BaseResource .SONOS_TYPE_HEADER ))
175+ .thenReturn (new BasicHeader (BaseResource .SONOS_TYPE_HEADER , "globalError" ));
176+ when (client .getHttpClient ().execute (any ())).thenReturn (mockedResponse );
177+ try
178+ {
179+ baseResource .getFromApi (SonosHomeTheaterOptions .class , "token123" , "some/test" );
180+ Assert .fail ("Did not handle error response correctly" );
181+ }
182+ catch (final SonosApiError e )
183+ {
184+ Assert .assertEquals (SonosErrorCode .ERROR_NOT_CAPABLE , e .getErrorCode ());
185+ }
186+ }
187+
188+ @ Test
189+ public void testApiMismatchHandledCorrectly () throws IOException , SonosApiClientException , SonosApiError
190+ {
191+ // Test data
192+ final SonosHomeTheaterOptions options = new SonosHomeTheaterOptions ();
193+ options .setNightMode (true );
194+ options .setEnhanceDialog (true );
195+ options .setGroupingLatency (50 );
196+
197+ // Mocks
198+ final HttpGet req = baseResource .getGetRequest ("token123" , "some/test" );
199+ final HttpEntity entity = new StringEntity (new ObjectMapper ().writeValueAsString (options ), ContentType .APPLICATION_JSON );
200+
201+ final CloseableHttpResponse mockedResponse = mock (CloseableHttpResponse .class );
202+ when (mockedResponse .getEntity ()).thenReturn (entity );
203+ final StatusLine sl = new BasicStatusLine (new ProtocolVersion ("HTTP" , 1 , 1 ), 200 , null );
204+ when (mockedResponse .getStatusLine ()).thenReturn (sl );
205+ when (mockedResponse .getFirstHeader (BaseResource .SONOS_TYPE_HEADER ))
206+ .thenReturn (new BasicHeader (BaseResource .SONOS_TYPE_HEADER , "audioClip" ));
207+ when (client .getHttpClient ().execute (any ())).thenReturn (mockedResponse );
208+ try
209+ {
210+ baseResource .getFromApi (SonosHomeTheaterOptions .class , "token123" , "some/test" );
211+ Assert .fail ("Did not handle error response correctly" );
212+ }
213+ catch (final SonosApiClientException e )
214+ {
215+ Assert .assertEquals ("Sonos declared SonosAudioClip as the response type, but the integration requested SonosHomeTheaterOptions" , e .getMessage ());
216+ }
217+ }
218+
219+ @ Test
220+ public void getStandardRequest () throws SonosApiClientException
221+ {
222+ final HttpGet req = baseResource .getStandardRequest (HttpGet .class , "token123" , "/some/path" );
223+ Assert .assertEquals (HttpGet .METHOD_NAME ,
224+ req .getMethod ());
225+
226+ Assert .assertEquals ("Bearer token123" ,
227+ req .getFirstHeader ("Authorization" ).getValue ());
228+
229+ Assert .assertEquals (
230+ "/control/api/some/path" ,
231+ req .getURI ().getPath ());
232+ }
233+
234+ @ Test
235+ public void testValidateNotNullNoFieldName () throws SonosApiClientException
236+ {
237+ baseResource .validateNotNull ("nonEmptyString" );
238+ }
239+
240+ @ Test (expected =SonosApiClientException .class )
241+ public void testValidateNotNullBothNulls () throws SonosApiClientException
242+ {
243+ baseResource .validateNotNull (null , null );
244+ }
245+
246+ @ Test (expected =SonosApiClientException .class )
247+ public void testValidateNotNullObjectNull () throws SonosApiClientException
248+ {
249+ baseResource .validateNotNull (null , "sonos-api-java" );
250+ }
251+
252+ @ Test (expected =SonosApiClientException .class )
253+ public void testValidateNotNullEmptyObject () throws SonosApiClientException
254+ {
255+ baseResource .validateNotNull ("" , "sonos-api-java" );
256+ }
257+
258+ @ Test
259+ public void testValidateNotNullNonEmptyObject () throws SonosApiClientException
260+ {
261+ baseResource .validateNotNull ("nonEmptyString" , "sonos-api-java" );
262+ }
263+ }
0 commit comments