// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.zookeeper;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.Collections;
import java.util.regex.Pattern;

import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.ProvisionInfo;
import com.yahoo.config.provision.Version;
import com.yahoo.path.Path;
import com.yahoo.text.Utf8;
import com.yahoo.vespa.config.server.TestWithCurator;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import com.yahoo.io.IOUtils;

public class ZKApplicationPackageTest extends TestWithCurator {

    private static final String APP = "src/test/apps/zkapp";
    private static final ProvisionInfo provisionInfo = ProvisionInfo.withHosts(
            Collections.singleton(new HostSpec("foo.yahoo.com", Collections.emptyList())));

    @Rule
    public TemporaryFolder tmpDir = new TemporaryFolder();

    @Test
    public void testBasicZKFeed() throws IOException {
        feed(configCurator, new File(APP));
        ZKApplicationPackage zkApp = new ZKApplicationPackage(configCurator, Path.fromString("/0"));
        assertTrue(Pattern.compile(".*<slobroks>.*",Pattern.MULTILINE+Pattern.DOTALL).matcher(IOUtils.readAll(zkApp.getServices())).matches());
        assertTrue(Pattern.compile(".*<alias>.*",Pattern.MULTILINE+Pattern.DOTALL).matcher(IOUtils.readAll(zkApp.getHosts())).matches());
        assertTrue(Pattern.compile(".*<slobroks>.*",Pattern.MULTILINE+Pattern.DOTALL).matcher(IOUtils.readAll(zkApp.getFile(Path.fromString("services.xml")).createReader())).matches());
        DeployState deployState = new DeployState.Builder().applicationPackage(zkApp).build();
        assertEquals(deployState.getSearchDefinitions().size(), 5);
        assertEquals(zkApp.searchDefinitionContents().size(), 5);
        assertEquals(IOUtils.readAll(zkApp.getRankingExpression("foo.expression")), "foo()+1\n");
        assertEquals(zkApp.getFiles(Path.fromString(""), "xml").size(), 3);
        assertEquals(zkApp.getFileReference(Path.fromString("components/file.txt")).getAbsolutePath(), "/home/vespa/test/file.txt");
        try (Reader foo = zkApp.getFile(Path.fromString("files/foo.json")).createReader()) {
            assertEquals(IOUtils.readAll(foo), "foo : foo\n");
        }
        try (Reader bar = zkApp.getFile(Path.fromString("files/sub/bar.json")).createReader()) {
            assertEquals(IOUtils.readAll(bar), "bar : bar\n");
        }
        assertTrue(zkApp.getFile(Path.createRoot()).exists());
        assertTrue(zkApp.getFile(Path.createRoot()).isDirectory());
        Version goodVersion = Version.fromIntValues(3, 0, 0);
        assertTrue(zkApp.getFileRegistryMap().containsKey(goodVersion));
        assertFalse(zkApp.getFileRegistryMap().containsKey(Version.fromIntValues(0, 0, 0)));
        assertThat(zkApp.getFileRegistryMap().get(goodVersion).fileSourceHost(), is("dummyfiles"));
        assertTrue(zkApp.getProvisionInfoMap().containsKey(goodVersion));
        ProvisionInfo readInfo = zkApp.getProvisionInfoMap().get(goodVersion);
        assertThat(Utf8.toString(readInfo.toJson()), is(Utf8.toString(provisionInfo.toJson())));
        assertTrue(zkApp.getDeployment().isPresent());
        assertThat(DeploymentSpec.fromXml(zkApp.getDeployment().get()).globalServiceId().get(), is("mydisc"));
    }

    private void feed(ConfigCurator zk, File dirToFeed) throws IOException {
        assertTrue(dirToFeed.isDirectory());
        zk.feedZooKeeper(dirToFeed, "/0" + ConfigCurator.USERAPP_ZK_SUBPATH, null, true);
        String metaData = "{\"deploy\":{\"user\":\"foo\",\"from\":\"bar\",\"timestamp\":1},\"application\":{\"name\":\"foo\",\"checksum\":\"abc\",\"generation\":4,\"previousActiveGeneration\":3}}";
        zk.putData("/0", ConfigCurator.META_ZK_PATH, metaData);
        zk.putData("/0/" + ZKApplicationPackage.fileRegistryNode + "/3.0.0", "dummyfiles");
        zk.putData("/0/" + ZKApplicationPackage.allocatedHostsNode + "/3.0.0", provisionInfo.toJson());
    }

}

@@ -338,16 +338,43 @@
 ctions;%0A
+import java.util.Optional;%0A
 import j
@@ -504,16 +504,58 @@
 yState;%0A
+import com.yahoo.config.provision.Flavor;%0A
 import c
@@ -586,24 +586,71 @@
 n.HostSpec;%0A
+import com.yahoo.config.provision.NodeFlavors;%0A
 import com.y
@@ -725,24 +725,76 @@
 on.Version;%0A
+import com.yahoo.config.provisioning.FlavorsConfig;%0A
 import com.y
@@ -1134,16 +1134,189 @@
 zkapp%22;%0A
+    private static final String TEST_FLAVOR_NAME = %22test-flavor%22;%0A    private static final Optional%3CFlavor%3E TEST_FLAVOR = new MockNodeFlavors().getFlavor(TEST_FLAVOR_NAME);%0A
     priv
@@ -1474,16 +1474,47 @@
 tyList()
+, TEST_FLAVOR, Optional.empty()
 )));%0A%0A  
@@ -1788,16 +1788,52 @@
 ng(%22/0%22)
+, Optional.of(new MockNodeFlavors())
 );%0A     
@@ -3872,24 +3872,109 @@
 oJson())));%0A
+        assertThat(readInfo.getHosts().iterator().next().flavor(), is(TEST_FLAVOR));%0A
         asse
@@ -4811,10 +4811,374 @@
 %0A    %7D%0A%0A
+    private static class MockNodeFlavors extends NodeFlavors%7B%0A%0A        MockNodeFlavors() %7B super(flavorsConfig()); %7D%0A%0A        private static FlavorsConfig flavorsConfig() %7B%0A            return new FlavorsConfig(new FlavorsConfig.Builder()%0A                            .flavor(new FlavorsConfig.Flavor.Builder().name(TEST_FLAVOR_NAME))%0A            );%0A        %7D%0A    %7D%0A
 %7D%0A

Add flavor to ZKApplicationPackageTest.