// Copyright (c) 2017, Baidu.com, Inc. All Rights Reserved

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package com.baidu.palo.load;

import com.baidu.palo.analysis.LoadStmt;
import com.baidu.palo.catalog.Catalog;
import com.baidu.palo.common.FeConstants;
import com.baidu.palo.common.FeMetaVersion;
import com.baidu.palo.common.LoadException;
import com.google.common.collect.Maps;

import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Map;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Catalog.class })
public class DppConfigTest {

    @Test
    public void testNormal() throws LoadException {
        // mock catalog
        int clusterId = 10;
        Catalog catalog = EasyMock.createNiceMock(Catalog.class);
        EasyMock.expect(catalog.getClusterId()).andReturn(clusterId).anyTimes();
        EasyMock.replay(catalog);
        PowerMock.mockStatic(Catalog.class);
        EasyMock.expect(Catalog.getInstance()).andReturn(catalog).anyTimes();
        PowerMock.replay(Catalog.class);

        Map<String, String> configMap = Maps.newHashMap();
        configMap.put("hadoop_palo_path", "/user/palo2");
        configMap.put("hadoop_http_port", "1234");
        configMap.put("hadoop_configs", "mapred.job.tracker=127.0.0.1:111;fs.default.name=hdfs://127.0.0.1:112;"
                        + "hadoop.job.ugi=user,password;mapred.job.priority=NORMAL");
        DppConfig dppConfig = DppConfig.create(configMap);

        Assert.assertEquals(String.format("/user/palo2/%d/applications/%s", clusterId, FeConstants.dpp_version),
                dppConfig.getApplicationsPath());
        Assert.assertEquals(String.format("/user/palo2/%d/output", clusterId), dppConfig.getOutputPath());
        Assert.assertEquals("hdfs://127.0.0.1:112", dppConfig.getFsDefaultName());
        Assert.assertEquals("user,password", dppConfig.getHadoopJobUgiStr());
        Assert.assertEquals("127.0.0.1", dppConfig.getNameNodeHost());
        Assert.assertEquals(1234, dppConfig.getHttpPort());

        Map<String, String> hadoopConfigs = dppConfig.getHadoopConfigs();
        Assert.assertEquals(4, hadoopConfigs.size());
        Assert.assertEquals("NORMAL", hadoopConfigs.get("mapred.job.priority"));

        // update
        Map<String, String> newConfigMap = Maps.newHashMap();
        newConfigMap.put("hadoop_configs", "mapred.job.priority=VERY_HIGH");
        DppConfig newDppConfig = DppConfig.create(newConfigMap);
        dppConfig.update(newDppConfig);
        Assert.assertEquals(4, hadoopConfigs.size());
        Assert.assertEquals("VERY_HIGH", hadoopConfigs.get("mapred.job.priority"));

        newConfigMap.clear();
        newConfigMap.put(LoadStmt.BOS_ENDPOINT, "http://127.0.0.2:1234");
        newConfigMap.put(LoadStmt.BOS_ACCESSKEY, "123");
        newConfigMap.put(LoadStmt.BOS_SECRET_ACCESSKEY, "456");
        dppConfig.updateHadoopConfigs(newConfigMap);
        Assert.assertEquals(7, hadoopConfigs.size());
        Assert.assertEquals("http://127.0.0.2:1234", hadoopConfigs.get("fs.bos.endpoint"));
        Assert.assertEquals("123", hadoopConfigs.get("fs.bos.access.key"));
        Assert.assertEquals("456", hadoopConfigs.get("fs.bos.secret.access.key"));

        // clear
        dppConfig.clear();
        Assert.assertEquals(3, hadoopConfigs.size());
        Assert.assertFalse(hadoopConfigs.containsKey("mapred.job.priority"));
        Assert.assertTrue(hadoopConfigs.containsKey("fs.default.name"));
    }

    @Test(expected = LoadException.class)
    public void testHadoopConfigsNotEnough() throws LoadException {
        Map<String, String> configMap = Maps.newHashMap();
        configMap.put("hadoop_palo_path", "/user/palo2");
        configMap.put("hadoop_http_port", "1234");
        configMap.put("hadoop_configs", "mapred.job.tracker=127.0.0.1:111;fs.default.name=hdfs://127.0.0.1:112;");
        DppConfig dppConfig = DppConfig.create(configMap);

        dppConfig.check();
    }

    @Test(expected = LoadException.class)
    public void testBosParamsNotEnough() throws LoadException {
        Map<String, String> configMap = Maps.newHashMap();
        configMap.put(LoadStmt.BOS_ENDPOINT, "http://127.0.0.2:1234");
        configMap.put(LoadStmt.BOS_ACCESSKEY, "123");

        DppConfig dppConfig = new DppConfig();
        dppConfig.updateHadoopConfigs(configMap);
    }

    @Test
    public void testSerialization() throws Exception {
        // mock catalog
        PowerMock.mockStatic(Catalog.class);
        EasyMock.expect(Catalog.getCurrentCatalogJournalVersion()).andReturn(FeMetaVersion.VERSION_12).anyTimes();
        PowerMock.replay(Catalog.class);

        Map<String, String> configMap = Maps.newHashMap();
        configMap.put("hadoop_palo_path", "/user/palo2");
        configMap.put("hadoop_http_port", "1234");
        configMap.put("hadoop_configs", "mapred.job.tracker=127.0.0.1:111;fs.default.name=hdfs://127.0.0.1:112;"
                        + "hadoop.job.ugi=user,password;mapred.job.priority=NORMAL");
        DppConfig dppConfig = DppConfig.create(configMap);

        File file = new File("./dppConfigTest");
        file.createNewFile();
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
        dppConfig.write(dos);
        dos.flush();
        dos.close();

        DataInputStream dis = new DataInputStream(new FileInputStream(file));
        DppConfig newDppConfig = new DppConfig();
        newDppConfig.readFields(dis);
        dis.close();
        file.delete();

        Assert.assertEquals("/user/palo2", newDppConfig.getPaloPath());
        Assert.assertEquals(1234, newDppConfig.getHttpPort());
        Assert.assertEquals(4, newDppConfig.getHadoopConfigs().size());
    }
}
