@Test
public void testInitialize() throws Exception {

    OAuthCertBoundJwtAccessTokenAuthority authority = new OAuthCertBoundJwtAccessTokenAuthority();
    // authenticateChallenge
    Field authenticateChallengeField = authority.getClass().getDeclaredField("authenticateChallenge");
    authenticateChallengeField.setAccessible(true);
    System.setProperty("athenz.auth.oauth.jwt.authn_challenge_realm", "https://realm.athenz.io");
    authority.initialize();
    System.clearProperty("athenz.auth.oauth.jwt.authn_challenge_realm");
    assertEquals(authenticateChallengeField.get(authority), "Bearer realm=\"https://realm.athenz.io\"");
    System.clearProperty("athenz.auth.oauth.jwt.authn_challenge_realm");
    authority.initialize();
    assertEquals(authenticateChallengeField.get(authority), "Bearer realm=\"https://athenz.io\"");
    // certificateIdentityParser
    CertificateIdentityParser certParser = null;
    Field excludeRoleCertificatesField = null, excludedPrincipalsField = null;
    Field certificateIdentityParserField = authority.getClass().getDeclaredField("certificateIdentityParser");
    certificateIdentityParserField.setAccessible(true);
    System.setProperty("athenz.auth.oauth.jwt.cert.exclude_role_certificates", "true");
    System.setProperty("athenz.auth.oauth.jwt.cert.excluded_principals", "principals_1,principals_2");
    authority.initialize();
    System.clearProperty("athenz.auth.oauth.jwt.cert.exclude_role_certificates");
    System.clearProperty("athenz.auth.oauth.jwt.cert.excluded_principals");
    certParser = (CertificateIdentityParser) certificateIdentityParserField.get(authority);
    excludeRoleCertificatesField  = certParser.getClass().getDeclaredField("excludeRoleCertificates");
    excludedPrincipalsField  = certParser.getClass().getDeclaredField("excludedPrincipalSet");
    excludeRoleCertificatesField.setAccessible(true);
    excludedPrincipalsField.setAccessible(true);
    assertEquals(excludeRoleCertificatesField.get(certParser), true);
    assertEquals(excludedPrincipalsField.get(certParser), new HashSet<>(Arrays.asList(new String[]{ "principals_1", "principals_2" })));
    System.clearProperty("athenz.auth.oauth.jwt.cert.exclude_role_certificates");
    System.clearProperty("athenz.auth.oauth.jwt.cert.excluded_principals");
    authority.initialize();
    certParser = (CertificateIdentityParser) certificateIdentityParserField.get(authority);
    excludeRoleCertificatesField  = certParser.getClass().getDeclaredField("excludeRoleCertificates");
    excludedPrincipalsField  = certParser.getClass().getDeclaredField("excludedPrincipalSet");
    excludeRoleCertificatesField.setAccessible(true);
    excludedPrincipalsField.setAccessible(true);
    assertEquals(excludeRoleCertificatesField.get(certParser), false);
    assertEquals(excludedPrincipalsField.get(certParser), (Set<String>) null);
    // parser
    Field parserField = authority.getClass().getDeclaredField("parser");
    parserField.setAccessible(true);
    System.setProperty("athenz.auth.oauth.jwt.parser_factory_class", "invalid_class");
    assertThrows(IllegalArgumentException.class, () -> authority.initialize());
    System.clearProperty("athenz.auth.oauth.jwt.parser_factory_class");
    System.setProperty("athenz.auth.oauth.jwt.parser_factory_class", OAuthCertBoundJwtAccessTokenAuthorityTestParserFactory.class.getName());
    authority.initialize();
    System.clearProperty("athenz.auth.oauth.jwt.parser_factory_class");
    assertTrue(parserField.get(authority) instanceof OAuthCertBoundJwtAccessTokenAuthorityTestParser);
    System.clearProperty("athenz.auth.oauth.jwt.parser_factory_class");
    authority.initialize();
    assertTrue(parserField.get(authority) instanceof DefaultOAuthJwtAccessTokenParser);
    // shouldVerifyCertThumbprint
    Field shouldVerifyCertThumbprintField = authority.getClass().getDeclaredField("shouldVerifyCertThumbprint");
    shouldVerifyCertThumbprintField.setAccessible(true);
    System.clearProperty("athenz.auth.oauth.jwt.verify_cert_thumbprint");
    authority.initialize();
    assertEquals(shouldVerifyCertThumbprintField.get(authority), true);
    System.setProperty("athenz.auth.oauth.jwt.verify_cert_thumbprint", "false");
    authority.initialize();
    System.clearProperty("athenz.auth.oauth.jwt.verify_cert_thumbprint");
    assertEquals(shouldVerifyCertThumbprintField.get(authority), false);
    // authorizedServices & validator
    DefaultOAuthJwtAccessTokenValidator validator = null;
    Field trustedIssuerField = null, requiredAudiencesField = null, requiredScopesField = null, authorizedClientIdsField = null;
    Field authorizedServicesField = authority.getClass().getDeclaredField("authorizedServices");
    authorizedServicesField.setAccessible(true);
    Field validatorField = authority.getClass().getDeclaredField("validator");
    validatorField.setAccessible(true);
    System.setProperty("athenz.auth.oauth.jwt.authorized_client_ids_path", "");
    System.setProperty("athenz.auth.oauth.jwt.claim.iss", "");
    System.setProperty("athenz.auth.oauth.jwt.claim.aud", "");
    System.setProperty("athenz.auth.oauth.jwt.claim.scope", "");
    assertThrows(IllegalArgumentException.class, () -> authority.initialize());
    System.clearProperty("athenz.auth.oauth.jwt.authorized_client_ids_path");
    System.clearProperty("athenz.auth.oauth.jwt.claim.iss");
    System.clearProperty("athenz.auth.oauth.jwt.claim.aud");
    System.clearProperty("athenz.auth.oauth.jwt.claim.scope");
    Map<String, String> expectedAuthorizedServices = new HashMap<>();
    Map<String, Set<String>> expectedAuthorizedClientIds = new HashMap<>();
    expectedAuthorizedServices.put("ui.athenz.io", "sys.auth.ui");
    expectedAuthorizedClientIds.put("ui.athenz.io", new HashSet<>(Arrays.asList(new String[]{"client_id_1","client_id_2","ui.athenz.io"})));
    System.setProperty("athenz.auth.oauth.jwt.authorized_client_ids_path", this.classLoader.getResource("authorized_client_ids.single.txt").getPath());
    System.setProperty("athenz.auth.oauth.jwt.claim.iss", "iss");
    System.setProperty("athenz.auth.oauth.jwt.claim.aud", "aud_1,aud_2");
    System.setProperty("athenz.auth.oauth.jwt.claim.scope", "scope_1 scope_2");
    authority.initialize();
    System.clearProperty("athenz.auth.oauth.jwt.authorized_client_ids_path");
    System.clearProperty("athenz.auth.oauth.jwt.claim.iss");
    System.clearProperty("athenz.auth.oauth.jwt.claim.aud");
    System.clearProperty("athenz.auth.oauth.jwt.claim.scope");
    assertEquals(authorizedServicesField.get(authority), expectedAuthorizedServices);
    validator = (DefaultOAuthJwtAccessTokenValidator) validatorField.get(authority);
    trustedIssuerField = validator.getClass().getDeclaredField("trustedIssuer");
    requiredAudiencesField = validator.getClass().getDeclaredField("requiredAudiences");
    requiredScopesField = validator.getClass().getDeclaredField("requiredScopes");
    authorizedClientIdsField = validator.getClass().getDeclaredField("authorizedClientIds");
    trustedIssuerField.setAccessible(true);
    requiredAudiencesField.setAccessible(true);
    requiredScopesField.setAccessible(true);
    authorizedClientIdsField.setAccessible(true);
    assertEquals(trustedIssuerField.get(validator), "iss");
    assertEquals(requiredAudiencesField.get(validator), new HashSet<>(Arrays.asList(new String[]{"aud_1", "aud_2"})));
    assertEquals(requiredScopesField.get(validator), new HashSet<>(Arrays.asList(new String[]{"scope_1", "scope_2"})));
    assertEquals(authorizedClientIdsField.get(validator), expectedAuthorizedClientIds);
    System.clearProperty("athenz.auth.oauth.jwt.authorized_client_ids_path");
    System.clearProperty("athenz.auth.oauth.jwt.claim.iss");
    System.clearProperty("athenz.auth.oauth.jwt.claim.aud");
    System.clearProperty("athenz.auth.oauth.jwt.claim.scope");
    authority.initialize();
    assertEquals(authorizedServicesField.get(authority), new HashMap<String, String>());
    validator = (DefaultOAuthJwtAccessTokenValidator) validatorField.get(authority);
    trustedIssuerField = validator.getClass().getDeclaredField("trustedIssuer");
    requiredAudiencesField = validator.getClass().getDeclaredField("requiredAudiences");
    requiredScopesField = validator.getClass().getDeclaredField("requiredScopes");
    authorizedClientIdsField = validator.getClass().getDeclaredField("authorizedClientIds");
    trustedIssuerField.setAccessible(true);
    requiredAudiencesField.setAccessible(true);
    requiredScopesField.setAccessible(true);
    authorizedClientIdsField.setAccessible(true);
    assertEquals(trustedIssuerField.get(validator), "https://athenz.io");
    assertEquals(requiredAudiencesField.get(validator), new HashSet<>(Arrays.asList(new String[]{"https://zms.athenz.io"})));
    assertEquals(requiredScopesField.get(validator), new HashSet<>(Arrays.asList(new String[]{"sys.auth:role.admin"})));
    assertEquals(authorizedClientIdsField.get(validator), new HashMap<String, String>());
}