@Test
  public void testGetServiceConfigurationUpdates() throws Exception {
    KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);

    final Host hostA = createMockHost("hostA");
    final Host hostB = createMockHost("hostB");
    final Host hostC = createMockHost("hostC");

    Collection<Host> hosts = Arrays.asList(hostA, hostB, hostC);

    final Map<String, String> kerberosEnvProperties = new HashMap<String, String>() {
      {
        put(KerberosHelper.KDC_TYPE, "mit-kdc");
        put(KerberosHelper.DEFAULT_REALM, "FOOBAR.COM");
        put("case_insensitive_username_rules", "false");
        put(KerberosHelper.CREATE_AMBARI_PRINCIPAL, "false");
      }
    };

    final Config kerberosEnvConfig = createMock(Config.class);
    expect(kerberosEnvConfig.getProperties()).andReturn(kerberosEnvProperties).atLeastOnce();

    final Map<String, String> krb5ConfProperties = createMock(Map.class);

    final Config krb5ConfConfig = createMock(Config.class);
    expect(krb5ConfConfig.getProperties()).andReturn(krb5ConfProperties).atLeastOnce();

    final KerberosPrincipalDescriptor principalDescriptor1 = createMockPrincipalDescriptor(
        "service1/_HOST@${realm}", KerberosPrincipalType.SERVICE, "service1user", "service1-site/service.kerberos.principal");
    final KerberosPrincipalDescriptor principalDescriptor1a = createMockPrincipalDescriptor(
        "component1a/_HOST@${realm}", KerberosPrincipalType.SERVICE, "service1user", "service1-site/component1a.kerberos.principal");
    final KerberosPrincipalDescriptor principalDescriptor1b = createMockPrincipalDescriptor(
        "component1b/_HOST@${realm}", KerberosPrincipalType.SERVICE, "service1user", "service1-site/component1b.kerberos.principal");
    final KerberosPrincipalDescriptor principalDescriptor2a = createMockPrincipalDescriptor(
        "component2a/_HOST@${realm}", KerberosPrincipalType.SERVICE, "service2user", "service2-site/component2a.kerberos.principal");
    final KerberosPrincipalDescriptor principalDescriptor2b = createMockPrincipalDescriptor(
        "component2b/_HOST@${realm}", KerberosPrincipalType.SERVICE, "service2user", "service2-site/component2b.kerberos.principal");
    final KerberosPrincipalDescriptor principalDescriptor3a = createMockPrincipalDescriptor(
        "component3a/_HOST@${realm}", KerberosPrincipalType.SERVICE, "service3user", "service3-site/component3a.kerberos.principal");

    final KerberosKeytabDescriptor keytabDescriptor1 = createMockKeytabDescriptor(
        "keytab1", "service1-site/service.kerberos.keytab");
    final KerberosKeytabDescriptor keytabDescriptor1a = createMockKeytabDescriptor(
        "keytab1a", "service1-site/component1a.kerberos.keytab");
    final KerberosKeytabDescriptor keytabDescriptor1b = createMockKeytabDescriptor(
        "keytab1b", "service1-site/component1b.kerberos.keytab");
    final KerberosKeytabDescriptor keytabDescriptor2a = createMockKeytabDescriptor(
        "keytab2a", "service2-site/component2a.kerberos.keytab");
    final KerberosKeytabDescriptor keytabDescriptor2b = createMockKeytabDescriptor(
        "keytab2b", "service2-site/component2b.kerberos.keytab");
    final KerberosKeytabDescriptor keytabDescriptor3a = createMockKeytabDescriptor(
        "keytab3a", "service3-site/component3a.kerberos.keytab");

    final KerberosIdentityDescriptor identityDescriptor1 = createMockIdentityDescriptor(
        "identity1", principalDescriptor1, keytabDescriptor1);
    final KerberosIdentityDescriptor identityDescriptor1a = createMockIdentityDescriptor(
        "identity1a", principalDescriptor1a, keytabDescriptor1a);
    final KerberosIdentityDescriptor identityDescriptor1b = createMockIdentityDescriptor(
        "identity1b", principalDescriptor1b, keytabDescriptor1b);
    final KerberosIdentityDescriptor identityDescriptor2a = createMockIdentityDescriptor(
        "identity2a", principalDescriptor2a, keytabDescriptor2a);
    final KerberosIdentityDescriptor identityDescriptor2b = createMockIdentityDescriptor(
        "identity2b", principalDescriptor2b, keytabDescriptor2b);
    final KerberosIdentityDescriptor identityDescriptor3a = createMockIdentityDescriptor(
        "identity3a", principalDescriptor3a, keytabDescriptor3a);

    final KerberosComponentDescriptor componentDescriptor1a = createMockComponentDescriptor(
        "COMPONENT1A",
        new ArrayList<KerberosIdentityDescriptor>() {
          {
            add(identityDescriptor1a);
          }
        },
        new HashMap<String, KerberosConfigurationDescriptor>() {
          {
            put("service1-site", createMockConfigurationDescriptor(
                Collections.singletonMap("component1a.property", "${replacement1}")
            ));
          }
        });
    final KerberosComponentDescriptor componentDescriptor1b = createMockComponentDescriptor(
        "COMPONENT1B",
        new ArrayList<KerberosIdentityDescriptor>() {
          {
            add(identityDescriptor1b);
          }
        },
        new HashMap<String, KerberosConfigurationDescriptor>() {
          {
            put("service1-site", createMockConfigurationDescriptor(
                Collections.singletonMap("component1b.property", "${type1/replacement1}")
            ));
          }
        });
    final KerberosComponentDescriptor componentDescriptor2a = createMockComponentDescriptor(
        "COMPONENT2A",
        new ArrayList<KerberosIdentityDescriptor>() {
          {
            add(identityDescriptor2a);
          }
        },
        new HashMap<String, KerberosConfigurationDescriptor>() {
          {
            put("service2-site", createMockConfigurationDescriptor(
                Collections.singletonMap("component2a.property", "${type1/replacement2}")
            ));
          }
        });
    final KerberosComponentDescriptor componentDescriptor2b = createMockComponentDescriptor(
        "COMPONENT2B",
        new ArrayList<KerberosIdentityDescriptor>() {
          {
            add(identityDescriptor2b);
          }
        },
        new HashMap<String, KerberosConfigurationDescriptor>() {
          {
            put("service2-site", createMockConfigurationDescriptor(
                Collections.singletonMap("component2b.property", "${type2/replacement1}")
            ));
          }
        });
    final KerberosComponentDescriptor componentDescriptor3a = createMockComponentDescriptor(
        "COMPONENT3A",
        new ArrayList<KerberosIdentityDescriptor>() {
          {
            add(identityDescriptor3a);
          }
        },
        new HashMap<String, KerberosConfigurationDescriptor>() {
          {
            put("service3-site", createMockConfigurationDescriptor(
                Collections.singletonMap("component3a.property", "${type3/replacement1}")
            ));
            put("core-site", createMockConfigurationDescriptor(
                Collections.singletonMap("component3b.property", "${type3/replacement2}")
            ));
          }
        });

    final KerberosServiceDescriptor serviceDescriptor1 = createMockServiceDescriptor(
        "SERVICE1",
        new HashMap<String, KerberosComponentDescriptor>() {
          {
            put("COMPONENT1A", componentDescriptor1a);
            put("COMPONENT1B", componentDescriptor1b);
          }
        },
        new ArrayList<KerberosIdentityDescriptor>() {
          {
            add(identityDescriptor1);
          }
        },
        false);
    expect(serviceDescriptor1.getComponent("COMPONENT1A")).andReturn(componentDescriptor1a).times(2);
    expect(serviceDescriptor1.getComponent("COMPONENT1B")).andReturn(componentDescriptor1b).times(2);

    final KerberosServiceDescriptor serviceDescriptor2 = createMockServiceDescriptor(
        "SERVICE2",
        new HashMap<String, KerberosComponentDescriptor>() {
          {
            put("COMPONENT2A", componentDescriptor2a);
            put("COMPONENT2B", componentDescriptor2b);
          }
        },
        Collections.<KerberosIdentityDescriptor>emptyList(),
        false);
    expect(serviceDescriptor2.getComponent("COMPONENT2A")).andReturn(componentDescriptor2a).times(1);
    expect(serviceDescriptor2.getComponent("COMPONENT2B")).andReturn(componentDescriptor2b).times(1);

    final KerberosServiceDescriptor serviceDescriptor3 = createMockServiceDescriptor(
        "SERVICE3",
        new HashMap<String, KerberosComponentDescriptor>() {
          {
            put("COMPONENT3A", componentDescriptor3a);
          }
        },
        Collections.<KerberosIdentityDescriptor>emptyList(), false);
    expect(serviceDescriptor3.getComponent("COMPONENT3A")).andReturn(componentDescriptor3a).times(2);

    Map<String, KerberosServiceDescriptor> serviceDescriptorMap = new HashMap<>();
    serviceDescriptorMap.put("SERVICE1", serviceDescriptor1);
    serviceDescriptorMap.put("SERVICE2", serviceDescriptor2);
    serviceDescriptorMap.put("SERVICE3", serviceDescriptor3);

    final Map<String, String> kerberosDescriptorProperties = new HashMap<>();
    kerberosDescriptorProperties.put(KerberosHelper.DEFAULT_REALM, "${kerberos-env/realm}");

    final KerberosDescriptor kerberosDescriptor = createMock(KerberosDescriptor.class);
    expect(kerberosDescriptor.getProperties()).andReturn(kerberosDescriptorProperties).atLeastOnce();
    expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).atLeastOnce();
    expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).atLeastOnce();
    expect(kerberosDescriptor.getService("SERVICE3")).andReturn(serviceDescriptor3).atLeastOnce();
    expect(kerberosDescriptor.getServices()).andReturn(serviceDescriptorMap).atLeastOnce();
    expect(kerberosDescriptor.getProperty("additional_realms")).andReturn(null).atLeastOnce();
    expect(kerberosDescriptor.getIdentities(eq(true), EasyMock.anyObject())).andReturn(null).atLeastOnce();
    expect(kerberosDescriptor.getAuthToLocalProperties()).andReturn(Collections.singleton("core-site/auth.to.local")).atLeastOnce();

    setupKerberosDescriptor(kerberosDescriptor);

    RecommendationResponse.BlueprintConfigurations coreSiteRecommendation = createNiceMock(RecommendationResponse
        .BlueprintConfigurations.class);
    expect(coreSiteRecommendation.getProperties()).andReturn(Collections.singletonMap("newPropertyRecommendation", "newPropertyRecommendation"));

    RecommendationResponse.BlueprintConfigurations newTypeRecommendation = createNiceMock(RecommendationResponse.BlueprintConfigurations.class);
    expect(newTypeRecommendation.getProperties()).andReturn(Collections.singletonMap("newTypeRecommendation", "newTypeRecommendation"));

    RecommendationResponse.BlueprintConfigurations type1Recommendation = createNiceMock(RecommendationResponse.BlueprintConfigurations.class);
    expect(type1Recommendation.getProperties()).andReturn(Collections.singletonMap("replacement1", "not replaced"));

    RecommendationResponse.BlueprintConfigurations service1SiteRecommendation = createNiceMock(RecommendationResponse.BlueprintConfigurations.class);
    expect(service1SiteRecommendation.getProperties()).andReturn(Collections.singletonMap("component1b.property", "replaced value"));

    Map<String, RecommendationResponse.BlueprintConfigurations> configurations = new HashMap<>();
    configurations.put("core-site", coreSiteRecommendation);
    configurations.put("new-type", newTypeRecommendation);
    configurations.put("type1", type1Recommendation);
    configurations.put("service1-site", service1SiteRecommendation);

    RecommendationResponse.Blueprint blueprint = createMock(RecommendationResponse.Blueprint.class);
    expect(blueprint.getConfigurations()).andReturn(configurations).once();

    RecommendationResponse.Recommendation recommendations = createMock(RecommendationResponse.Recommendation.class);
    expect(recommendations.getBlueprint()).andReturn(blueprint).once();

    RecommendationResponse recommendationResponse = createMock(RecommendationResponse.class);
    expect(recommendationResponse.getRecommendations()).andReturn(recommendations).once();

    StackAdvisorHelper stackAdvisorHelper = injector.getInstance(StackAdvisorHelper.class);
    expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andReturn(null).once();
    expect(stackAdvisorHelper.recommend(anyObject(StackAdvisorRequest.class))).andReturn(recommendationResponse).once();

    final Service service1 = createMockService("SERVICE1",
        new HashMap<String, ServiceComponent>() {
          {
            put("COMPONENT1A", createMockComponent("COMPONENT1A", true,
                new HashMap<String, ServiceComponentHost>() {
                  {
                    put("hostA", createMockServiceComponentHost(State.INSTALLED));
                  }
                }));
            put("COMPONENT1B", createMockComponent("COMPONENT1B", false,
                new HashMap<String, ServiceComponentHost>() {
                  {
                    put("hostB", createMockServiceComponentHost(State.INSTALLED));
                    put("hostC", createMockServiceComponentHost(State.INSTALLED));
                  }
                }));
          }
        });
    final Service service2 = createMockService("SERVICE2",
        new HashMap<String, ServiceComponent>() {
          {
            put("COMPONENT2A", createMockComponent("COMPONENT2A", true,
                new HashMap<String, ServiceComponentHost>() {
                  {
                    put("hostA", createMockServiceComponentHost(State.INSTALLED));
                  }
                }));
            put("COMPONENT2B", createMockComponent("COMPONENT2B", false,
                new HashMap<String, ServiceComponentHost>() {
                  {
                    put("hostB", createMockServiceComponentHost(State.INSTALLED));
                    put("hostC", createMockServiceComponentHost(State.INSTALLED));
                  }
                }));
          }
        });
    final Service service3 = createMockService("SERVICE3",
        new HashMap<String, ServiceComponent>() {
          {
            put("COMPONENT3A", createMockComponent("COMPONENT3A", true,
                new HashMap<String, ServiceComponentHost>() {
                  {
                    put("hostA", createMockServiceComponentHost(State.INSTALLED));
                  }
                }));
          }
        });

    Map<String, Service> services = new HashMap<>();
    services.put("SERVICE1", service1);
    services.put("SERVICE2", service2);
    services.put("SERVICE3", service3);

    Map<String, Set<String>> serviceComponentHostMap = new HashMap<>();
    serviceComponentHostMap.put("COMPONENT1A", new TreeSet<>(Arrays.asList("hostA")));
    serviceComponentHostMap.put("COMPONENT1B", new TreeSet<>(Arrays.asList("hostB", "hostC")));
    serviceComponentHostMap.put("COMPONENT2A", new TreeSet<>(Arrays.asList("hostA")));
    serviceComponentHostMap.put("COMPONENT2B", new TreeSet<>(Arrays.asList("hostB", "hostC")));
    serviceComponentHostMap.put("COMPONEN3A", new TreeSet<>(Arrays.asList("hostA")));

    final Cluster cluster = createMockCluster("c1", hosts, SecurityType.KERBEROS, krb5ConfConfig, kerberosEnvConfig);
    expect(cluster.getServices()).andReturn(services).anyTimes();
    expect(cluster.getServiceComponentHostMap(EasyMock.anyObject(), EasyMock.anyObject())).andReturn(serviceComponentHostMap).anyTimes();
    expect(cluster.getDesiredStackVersion()).andReturn(new StackId("HDP-2.2")).anyTimes();

    final Map<String, Map<String, String>> existingConfigurations = new HashMap<String, Map<String, String>>() {
      {
        put("kerberos-env", kerberosEnvProperties);
        put("", new HashMap<String, String>() {
          {
            put("replacement1", "value1");
          }
        });
        put("type1", new HashMap<String, String>() {
          {
            put("replacement1", "value2");
            put("replacement2", "value3");
          }
        });
        put("type2", new HashMap<String, String>() {
          {
            put("replacement1", "value4");
            put("replacement2", "value5");
          }
        });
        put("type3", new HashMap<String, String>() {
          {
            put("replacement1", "value6");
            put("replacement2", "value7");
          }
        });
      }
    };

    replayAll();

    // Needed by infrastructure
    injector.getInstance(AmbariMetaInfo.class).init();

    HashMap<String, Set<String>> installedServices1 = new HashMap<>();
    installedServices1.put("SERVICE1", new HashSet<>(Arrays.asList("COMPONENT1A", "COMPONENT1B")));
    installedServices1.put("SERVICE2", new HashSet<>(Arrays.asList("COMPONENT2A", "COMPONENT2B")));
    installedServices1.put("SERVICE3", Collections.singleton("COMPONENT3A"));

    Map<String, Map<String, String>> updates1 = kerberosHelper.getServiceConfigurationUpdates(
        cluster, existingConfigurations, installedServices1, null, null, true, true);

    HashMap<String, Set<String>> installedServices2 = new HashMap<>();
    installedServices2.put("SERVICE1", new HashSet<>(Arrays.asList("COMPONENT1A", "COMPONENT1B")));
    installedServices2.put("SERVICE3", Collections.singleton("COMPONENT3A"));

    Map<String, Collection<String>> serviceFilter2 = new HashMap<>();
    serviceFilter2.put("SERVICE1", new HashSet<>(Arrays.asList("COMPONENT1A", "COMPONENT1B")));
    serviceFilter2.put("SERVICE3", Collections.singleton("COMPONENT3A"));

    Map<String, Map<String, String>> updates2 = kerberosHelper.getServiceConfigurationUpdates(
        cluster, existingConfigurations, installedServices2, serviceFilter2, null, true, true);

    verifyAll();

    Map<String, Map<String, String>> expectedUpdates = new HashMap<String, Map<String, String>>() {{
      put("service1-site", new HashMap<String, String>() {
        {
          put("service.kerberos.principal", "service1/_HOST@FOOBAR.COM");
          put("service.kerberos.keytab", "keytab1");
          put("component1a.kerberos.principal", "component1a/_HOST@FOOBAR.COM");
          put("component1a.kerberos.keytab", "keytab1a");
          put("component1a.property", "value1");
          put("component1b.kerberos.principal", "component1b/_HOST@FOOBAR.COM");
          put("component1b.kerberos.keytab", "keytab1b");
          put("component1b.property", "value2");
        }
      });
      put("service2-site", new HashMap<String, String>() {
        {
          put("component2a.kerberos.principal", "component2a/_HOST@FOOBAR.COM");
          put("component2a.kerberos.keytab", "keytab2a");
          put("component2a.property", "value3");
          put("component2b.kerberos.principal", "component2b/_HOST@FOOBAR.COM");
          put("component2b.kerberos.keytab", "keytab2b");
          put("component2b.property", "value4");
        }
      });
      put("service3-site", new HashMap<String, String>() {
        {
          put("component3a.kerberos.principal", "component3a/_HOST@FOOBAR.COM");
          put("component3a.kerberos.keytab", "keytab3a");
          put("component3a.property", "value6");
        }
      });
      put("core-site", new HashMap<String, String>() {
        {
          put("auth.to.local", "RULE:[1:$1@$0](.*@FOOBAR.COM)s/@.*//\n" +
              "RULE:[2:$1@$0](component1a@FOOBAR.COM)s/.*/service1user/\n" +
              "RULE:[2:$1@$0](component1b@FOOBAR.COM)s/.*/service1user/\n" +
              "RULE:[2:$1@$0](component2a@FOOBAR.COM)s/.*/service2user/\n" +
              "RULE:[2:$1@$0](component2b@FOOBAR.COM)s/.*/service2user/\n" +
              "RULE:[2:$1@$0](component3a@FOOBAR.COM)s/.*/service3user/\n" +
              "RULE:[2:$1@$0](service1@FOOBAR.COM)s/.*/service1user/\n" +
              "DEFAULT");
          put("component3b.property", "value7");
        }
      });
    }};

    assertEquals(expectedUpdates, updates1);

    expectedUpdates.remove("service2-site");
    expectedUpdates.get("core-site").put("newPropertyRecommendation", "newPropertyRecommendation");
    expectedUpdates.get("core-site").put("auth.to.local", "RULE:[1:$1@$0](.*@FOOBAR.COM)s/@.*//\n" +
        "RULE:[2:$1@$0](component1a@FOOBAR.COM)s/.*/service1user/\n" +
        "RULE:[2:$1@$0](component1b@FOOBAR.COM)s/.*/service1user/\n" +
        "RULE:[2:$1@$0](component3a@FOOBAR.COM)s/.*/service3user/\n" +
        "RULE:[2:$1@$0](service1@FOOBAR.COM)s/.*/service1user/\n" +
        "DEFAULT");
    expectedUpdates.get("service1-site").put("component1b.property", "replaced value");
    expectedUpdates.put("new-type", new HashMap<String, String>() {
      {
        put("newTypeRecommendation", "newTypeRecommendation");
      }
    });

    assertEquals(expectedUpdates, updates2);

    // Make sure the existing configurations remained unchanged
    Map<String, Map<String, String>> expectedExistingConfigurations = new HashMap<String, Map<String, String>>() {
      {
        put("kerberos-env", new HashMap<String, String>() {
          {
            put(KerberosHelper.KDC_TYPE, "mit-kdc");
            put(KerberosHelper.DEFAULT_REALM, "FOOBAR.COM");
            put("case_insensitive_username_rules", "false");
            put(KerberosHelper.CREATE_AMBARI_PRINCIPAL, "false");
          }
        });
        put("", new HashMap<String, String>() {
          {
            put("replacement1", "value1");
          }
        });
        put("type1", new HashMap<String, String>() {
          {
            put("replacement1", "value2");
            put("replacement2", "value3");
          }
        });
        put("type2", new HashMap<String, String>() {
          {
            put("replacement1", "value4");
            put("replacement2", "value5");
          }
        });
        put("type3", new HashMap<String, String>() {
          {
            put("replacement1", "value6");
            put("replacement2", "value7");
          }
        });
      }
    };

    assertEquals(expectedExistingConfigurations, existingConfigurations);
  }
Tests that when regenerating keytabs for an upgrade, that the retry allowed
boolean is set on the tasks created.

@throws Exception
ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java