5151import java .io .ByteArrayOutputStream ;
5252import java .io .IOException ;
5353import java .net .URLDecoder ;
54+ import java .util .ArrayList ;
5455import java .util .HashMap ;
5556import java .util .List ;
5657import java .util .Map ;
@@ -62,6 +63,8 @@ public class FirebaseRemoteConfigClientImplTest {
6263
6364 private static final String TEST_REMOTE_CONFIG_URL =
6465 "https://firebaseremoteconfig.googleapis.com/v1/projects/test-project/remoteConfig" ;
66+ private static final String TEST_SERVER_REMOTE_CONFIG_URL =
67+ "https://firebaseremoteconfig.googleapis.com/v1/projects/test-project/namespaces/firebase-server/serverRemoteConfig" ;
6568
6669 private static final List <Integer > HTTP_STATUS_CODES = ImmutableList .of (401 , 404 , 500 );
6770
@@ -72,6 +75,9 @@ public class FirebaseRemoteConfigClientImplTest {
7275
7376 private static final String MOCK_TEMPLATE_RESPONSE = TestUtils
7477 .loadResource ("getRemoteConfig.json" );
78+
79+ private static final String MOCK_SERVER_TEMPLATE_RESPONSE = TestUtils
80+ .loadResource ("getServerRemoteConfig.json" );
7581
7682 private static final String MOCK_LIST_VERSIONS_RESPONSE = TestUtils
7783 .loadResource ("listRemoteConfigVersions.json" );
@@ -110,6 +116,13 @@ public class FirebaseRemoteConfigClientImplTest {
110116 "device.os == 'android' && device.country in ['us', 'uk']" )
111117 );
112118
119+ private static final List <ServerCondition > EXPECTED_SERVER_CONDITIONS = new ArrayList <ServerCondition >(List .of (
120+ new ServerCondition ("custom_signal" ,null ).setServerCondition (new OneOfCondition ().setOrCondition (new OrCondition (ImmutableList .of (new OneOfCondition ().setAndCondition (new AndCondition (ImmutableList .of (new OneOfCondition ().setCustomSignal (new CustomSignalCondition ("users" , CustomSignalOperator .NUMERIC_LESS_THAN , new ArrayList <>(List .of ("100" ))))))))))),
121+ new ServerCondition ("percent" ,null ).setServerCondition (new OneOfCondition ().setOrCondition (new OrCondition (ImmutableList .of (new OneOfCondition ().setAndCondition (new AndCondition (ImmutableList .of (new OneOfCondition ().setPercent (new PercentCondition (new MicroPercentRange (12000000 , 100000000 ), PercentConditionOperator .BETWEEN , "3maarirs9xzs" ))))))))),
122+ new ServerCondition ("chained_conditions" ,null ).setServerCondition (new OneOfCondition ().setOrCondition (new OrCondition (ImmutableList .of (new OneOfCondition ().setAndCondition (new AndCondition (ImmutableList .of (new OneOfCondition ().setCustomSignal (new CustomSignalCondition ("users" , CustomSignalOperator .NUMERIC_LESS_THAN , new ArrayList <>(List .of ("100" )))), new OneOfCondition ().setPercent (new PercentCondition (new MicroPercentRange (25000000 , 100000000 ), PercentConditionOperator .BETWEEN , "cla24qoibb61" ))))))))))
123+ );
124+
125+
113126 private static final Version EXPECTED_VERSION = new Version (new TemplateResponse .VersionResponse ()
114127 .setVersionNumber ("17" )
115128 .setUpdateOrigin ("ADMIN_SDK_NODE" )
@@ -128,6 +141,13 @@ public class FirebaseRemoteConfigClientImplTest {
128141 .setConditions (EXPECTED_CONDITIONS )
129142 .setParameterGroups (EXPECTED_PARAMETER_GROUPS )
130143 .setVersion (EXPECTED_VERSION );
144+
145+ private static final ServerTemplateData EXPECT_SERVER_TEMPLATE_DATA = new ServerTemplateData ()
146+ .setETag (TEST_ETAG )
147+ .setParameters (EXPECTED_PARAMETERS )
148+ .setParameterGroups (EXPECTED_PARAMETER_GROUPS )
149+ .setServerConditions (EXPECTED_SERVER_CONDITIONS )
150+ .setVersion (EXPECTED_VERSION );
131151
132152 private MockLowLevelHttpResponse response ;
133153 private TestResponseInterceptor interceptor ;
@@ -1188,6 +1208,19 @@ private void checkGetRequestHeader(HttpRequest request, String urlSuffix) {
11881208 assertEquals ("gzip" , headers .getAcceptEncoding ());
11891209 }
11901210
1211+ private void checkGetRequestHeaderForServer (HttpRequest request ) {
1212+ checkGetRequestHeaderForServer (request , "" );
1213+ }
1214+
1215+ private void checkGetRequestHeaderForServer (HttpRequest request , String urlSuffix ) {
1216+ assertEquals ("GET" , request .getRequestMethod ());
1217+ assertEquals (TEST_SERVER_REMOTE_CONFIG_URL + urlSuffix , request .getUrl ().toString ());
1218+ HttpHeaders headers = request .getHeaders ();
1219+ assertEquals ("fire-admin-java/" + SdkUtils .getVersion (), headers .get ("X-Firebase-Client" ));
1220+ assertEquals (SdkUtils .getMetricsHeader (), request .getHeaders ().get ("X-Goog-Api-Client" ));
1221+ assertEquals ("gzip" , headers .getAcceptEncoding ());
1222+ }
1223+
11911224 private void checkPutRequestHeader (HttpRequest request ) {
11921225 checkPutRequestHeader (request , "" , TEST_ETAG );
11931226 }
@@ -1237,4 +1270,202 @@ private void checkExceptionFromHttpResponse(
12371270 assertEquals (httpMethod , request .getMethod ());
12381271 assertTrue (request .getUrl ().startsWith ("https://firebaseremoteconfig.googleapis.com" ));
12391272 }
1273+
1274+
1275+
1276+ // Get server template tests
1277+
1278+
1279+ @ Test
1280+ public void testGetServerTemplate () throws Exception {
1281+ response .addHeader ("etag" , TEST_ETAG );
1282+ response .setContent (MOCK_SERVER_TEMPLATE_RESPONSE );
1283+
1284+ String receivedTemplate = client .getServerTemplate ();
1285+ ServerTemplateData serverTemplateData = ServerTemplateData .fromJSON (receivedTemplate );
1286+
1287+ assertEquals (EXPECTED_PARAMETERS , serverTemplateData .getParameters ());
1288+ assertEquals (TEST_ETAG , serverTemplateData .getETag ());
1289+ assertEquals (EXPECTED_SERVER_CONDITIONS , serverTemplateData .getServerConditions ());
1290+ // assertEquals(EXPECT_SERVER_TEMPLATE_DATA, serverTemplateData);
1291+ assertEquals (1605423446000L , serverTemplateData .getVersion ().getUpdateTime ());
1292+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1293+ }
1294+
1295+ @ Test
1296+ public void testGetServerTemplateWithTimestampUpToNanosecondPrecision () throws Exception {
1297+ List <String > timestamps = ImmutableList .of (
1298+ "2020-11-15T06:57:26.342Z" ,
1299+ "2020-11-15T06:57:26.342763Z" ,
1300+ "2020-11-15T06:57:26.342763941Z"
1301+ );
1302+ for (String timestamp : timestamps ) {
1303+ response .addHeader ("etag" , TEST_ETAG );
1304+ String templateResponse = "{\" version\" : {"
1305+ + " \" versionNumber\" : \" 17\" ,"
1306+ + " \" updateTime\" : \" " + timestamp + "\" "
1307+ + " }}" ;
1308+ response .setContent (templateResponse );
1309+
1310+ String receivedTemplate = client .getServerTemplate ();
1311+ ServerTemplateData serverTemplateData = ServerTemplateData .fromJSON (receivedTemplate );
1312+
1313+ assertEquals (TEST_ETAG , serverTemplateData .getETag ());
1314+ assertEquals ("17" , serverTemplateData .getVersion ().getVersionNumber ());
1315+ assertEquals (1605423446000L , serverTemplateData .getVersion ().getUpdateTime ());
1316+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1317+ }
1318+ }
1319+
1320+ @ Test
1321+ public void testGetServerTemplateWithEmptyTemplateResponse () throws Exception {
1322+ response .addHeader ("etag" , TEST_ETAG );
1323+ response .setContent ("{}" );
1324+
1325+
1326+ String receivedTemplate = client .getServerTemplate ();
1327+ ServerTemplateData serverTemplateData = ServerTemplateData .fromJSON (receivedTemplate );
1328+
1329+ assertEquals (TEST_ETAG , serverTemplateData .getETag ());
1330+ assertEquals (0 , serverTemplateData .getParameters ().size ());
1331+ assertEquals (0 , serverTemplateData .getServerConditions ().size ());
1332+ assertEquals (0 , serverTemplateData .getParameterGroups ().size ());
1333+ assertNull (serverTemplateData .getVersion ());
1334+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1335+ }
1336+
1337+ @ Test (expected = IllegalStateException .class )
1338+ public void testGetServerTemplateWithNoEtag () throws FirebaseRemoteConfigException {
1339+ // ETag does not exist
1340+ response .setContent (MOCK_SERVER_TEMPLATE_RESPONSE );
1341+
1342+ client .getServerTemplate ();
1343+ }
1344+
1345+ @ Test (expected = IllegalStateException .class )
1346+ public void testGetServerTemplateWithEmptyEtag () throws FirebaseRemoteConfigException {
1347+ // Empty ETag
1348+ response .addHeader ("etag" , "" );
1349+ response .setContent (MOCK_SERVER_TEMPLATE_RESPONSE );
1350+
1351+ client .getServerTemplate ();
1352+ }
1353+
1354+ @ Test
1355+ public void testGetServerTemplateHttpError () {
1356+ for (int code : HTTP_STATUS_CODES ) {
1357+ response .setStatusCode (code ).setContent ("{}" );
1358+
1359+ try {
1360+ client .getServerTemplate ();
1361+ fail ("No error thrown for HTTP error" );
1362+ } catch (FirebaseRemoteConfigException error ) {
1363+ checkExceptionFromHttpResponse (error , HTTP_STATUS_TO_ERROR_CODE .get (code ), null ,
1364+ "Unexpected HTTP response with status: " + code + "\n {}" , HttpMethods .GET );
1365+ }
1366+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1367+ }
1368+ }
1369+
1370+ @ Test
1371+ public void testGetServerTemplateTransportError () {
1372+ client = initClientWithFaultyTransport ();
1373+
1374+ try {
1375+ client .getServerTemplate ();
1376+ fail ("No error thrown for HTTP error" );
1377+ } catch (FirebaseRemoteConfigException error ) {
1378+ assertEquals (ErrorCode .UNKNOWN , error .getErrorCode ());
1379+ assertEquals ("Unknown error while making a remote service call: transport error" ,
1380+ error .getMessage ());
1381+ assertTrue (error .getCause () instanceof IOException );
1382+ assertNull (error .getHttpResponse ());
1383+ assertNull (error .getRemoteConfigErrorCode ());
1384+ }
1385+ }
1386+
1387+ @ Test
1388+ public void testGetServerTemplateSuccessResponseWithUnexpectedPayload () {
1389+ response .setContent ("not valid json" );
1390+
1391+ try {
1392+ client .getServerTemplate ();
1393+ fail ("No error thrown for malformed response" );
1394+ } catch (FirebaseRemoteConfigException error ) {
1395+ assertEquals (ErrorCode .UNKNOWN , error .getErrorCode ());
1396+ assertTrue (error .getMessage ().startsWith ("Error while parsing HTTP response: " ));
1397+ assertNotNull (error .getCause ());
1398+ assertNotNull (error .getHttpResponse ());
1399+ assertNull (error .getRemoteConfigErrorCode ());
1400+ }
1401+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1402+ }
1403+
1404+ @ Test
1405+ public void testGetServerTemplateErrorWithZeroContentResponse () {
1406+ for (int code : HTTP_STATUS_CODES ) {
1407+ response .setStatusCode (code ).setZeroContent ();
1408+
1409+ try {
1410+ client .getServerTemplate ();
1411+ fail ("No error thrown for HTTP error" );
1412+ } catch (FirebaseRemoteConfigException error ) {
1413+ checkExceptionFromHttpResponse (error , HTTP_STATUS_TO_ERROR_CODE .get (code ), null ,
1414+ "Unexpected HTTP response with status: " + code + "\n null" , HttpMethods .GET );
1415+ }
1416+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1417+ }
1418+ }
1419+
1420+ @ Test
1421+ public void testGetServerTemplateErrorWithMalformedResponse () {
1422+ for (int code : HTTP_STATUS_CODES ) {
1423+ response .setStatusCode (code ).setContent ("not json" );
1424+
1425+ try {
1426+ client .getServerTemplate ();
1427+ fail ("No error thrown for HTTP error" );
1428+ } catch (FirebaseRemoteConfigException error ) {
1429+ checkExceptionFromHttpResponse (error , HTTP_STATUS_TO_ERROR_CODE .get (code ), null ,
1430+ "Unexpected HTTP response with status: " + code + "\n not json" , HttpMethods .GET );
1431+ }
1432+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1433+ }
1434+ }
1435+
1436+ @ Test
1437+ public void testGetServerTemplateErrorWithDetails () {
1438+ for (int code : HTTP_STATUS_CODES ) {
1439+ response .setStatusCode (code ).setContent (
1440+ "{\" error\" : {\" status\" : \" INVALID_ARGUMENT\" , \" message\" : \" test error\" }}" );
1441+
1442+ try {
1443+ client .getServerTemplate ();
1444+ fail ("No error thrown for HTTP error" );
1445+ } catch (FirebaseRemoteConfigException error ) {
1446+ checkExceptionFromHttpResponse (error , ErrorCode .INVALID_ARGUMENT , null , "test error" ,
1447+ HttpMethods .GET );
1448+ }
1449+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1450+ }
1451+ }
1452+
1453+ @ Test
1454+ public void testGetServerTemplateErrorWithRcError () {
1455+ for (int code : HTTP_STATUS_CODES ) {
1456+ response .setStatusCode (code ).setContent (
1457+ "{\" error\" : {\" status\" : \" INVALID_ARGUMENT\" , "
1458+ + "\" message\" : \" [INVALID_ARGUMENT]: test error\" }}" );
1459+
1460+ try {
1461+ client .getServerTemplate ();
1462+ fail ("No error thrown for HTTP error" );
1463+ } catch (FirebaseRemoteConfigException error ) {
1464+ checkExceptionFromHttpResponse (error , ErrorCode .INVALID_ARGUMENT ,
1465+ RemoteConfigErrorCode .INVALID_ARGUMENT , "[INVALID_ARGUMENT]: test error" ,
1466+ HttpMethods .GET );
1467+ }
1468+ checkGetRequestHeaderForServer (interceptor .getLastRequest ());
1469+ }
12401470}
1471+ }
0 commit comments