Package com.asakusafw.testdriver

Source Code of com.asakusafw.testdriver.FlowPartTestDriver

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* Licensed 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.asakusafw.testdriver;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.lib.output.FileOutputCommitter;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.asakusafw.compiler.flow.FlowDescriptionDriver;
import com.asakusafw.compiler.flow.Location;
import com.asakusafw.compiler.testing.DirectExporterDescription;
import com.asakusafw.compiler.testing.DirectFlowCompiler;
import com.asakusafw.compiler.testing.DirectImporterDescription;
import com.asakusafw.compiler.testing.JobflowInfo;
import com.asakusafw.runtime.util.VariableTable;
import com.asakusafw.testdriver.hadoop.ConfigurationFactory;
import com.asakusafw.testtools.TestUtils;
import com.asakusafw.vocabulary.external.ExporterDescription;
import com.asakusafw.vocabulary.external.ImporterDescription;
import com.asakusafw.vocabulary.flow.FlowDescription;
import com.asakusafw.vocabulary.flow.In;
import com.asakusafw.vocabulary.flow.Out;
import com.asakusafw.vocabulary.flow.graph.FlowGraph;

/**
* フロー部品用のテストドライバクラス。
*/
@SuppressWarnings("deprecation")
public class FlowPartTestDriver extends TestDriverTestToolsBase {

    private static final Logger LOG = LoggerFactory.getLogger(FlowPartTestDriver.class);

    private final FlowDescriptionDriver flowDescriptionDriver = new FlowDescriptionDriver();

    private final Map<String, List<String>> createInMap = new HashMap<String, List<String>>();
    private final Map<String, List<String>> createOutMap = new HashMap<String, List<String>>();

    private boolean createIndividually = false;
    private boolean loadIndividually = false;

    /**
     * コンストラクタ。
     *
     * @throws RuntimeException インスタンスの生成に失敗した場合
     */
    public FlowPartTestDriver() {
        super();
    }

    /**
     * コンストラクタ。
     *
     * @param testDataFileList テストデータ定義シートのパスを示すFileのリスト
     * @throws RuntimeException インスタンスの生成に失敗した場合
     * @see FlowPartTestDriver#FlowPartTestDriver()
     */
    public FlowPartTestDriver(List<File> testDataFileList) {
        super(testDataFileList);
    }

    /**
     * フロー部品のテストを実行し、テスト結果を検証します。
     *
     * @param flowDescription フロー部品クラスのインスタンス
     */
    public void runTest(FlowDescription flowDescription) {

        try {
            // フローコンパイラの実行
            String batchId = "flow";
            String flowId = "part";
            File compileWorkDir = driverContext.getCompilerWorkingDirectory();
            if (compileWorkDir.exists()) {
                FileUtils.forceDelete(compileWorkDir);
            }

            FlowGraph flowGraph = flowDescriptionDriver.createFlowGraph(flowDescription);
            JobflowInfo jobflowInfo = DirectFlowCompiler.compile(flowGraph, batchId, flowId, "test.flowpart",
                    FlowPartDriverUtils.createWorkingLocation(driverContext), compileWorkDir,
                    Arrays.asList(new File[] { DirectFlowCompiler.toLibraryPath(flowDescription.getClass()) }),
                    flowDescription.getClass().getClassLoader(), driverContext.getOptions());

            JobflowExecutor executor = new JobflowExecutor(driverContext);
            driverContext.prepareCurrentJobflow(jobflowInfo);

            // クラスタワークディレクトリ初期化
            executor.cleanWorkingDirectory();

            // テストデータ生成ツールを実行し、Excel上のテストデータ定義からシーケンスファイルを生成し、HDFS上に配置する。
            if (createIndividually) {
                prepareIndividually();
            } else {
                createAllInput();
            }

            executor.runJobflow(jobflowInfo);

            // テスト結果検証ツールを実行し、Excel上の期待値とシーケンスファイル上の実際値を比較する。
            if (loadIndividually) {
                loadAndInspectResultsIndividually();
            } else {
                loadAndInspectResults();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            driverContext.cleanUpTemporaryResources();
        }
    }

    /**
     * フロー部品の入力オブジェクトを生成します。
     *
     * @param <T> データモデルクラス
     * @param tableName テーブル名
     * @return 入力インターフェース
     */
    @SuppressWarnings("unchecked")
    public <T> In<T> createIn(String tableName) {

        Class<?> modelType = testUtils.getClassByTablename(tableName);
        return (In<T>) createIn(modelType);
    }

    /**
     * フロー部品の入力オブジェクトを生成します。
     *
     * @param <T> データモデルクラス
     * @param modelType データモデルクラス
     * @return 入力インターフェース
     */
    public <T> In<T> createIn(Class<T> modelType) {

        String tableName = testUtils.getTablenameByClass(modelType);
        addCreateIn(tableName, tableName);
        String path = FlowPartDriverUtils.createInputLocation(driverContext, tableName).toPath('/');
        LOG.info("DirectImporterDescription生成:Path=" + path);
        ImporterDescription desc = new DirectImporterDescription(modelType, path);
        return flowDescriptionDriver.createIn(tableName, desc);
    }

    /**
     * フロー部品の入力オブジェクトを生成します。
     * <p>
     * フロー部品の入力に同一モデル(テーブル)が複数存在する場合は このメソッドを使います。
     * </p>
     *
     * @param <T> データモデルクラス
     * @param tableName テーブル名
     * @param excelFileName テストデータ定義シートファイル名(.xlsを除いた値)
     * @return 入力インターフェース
     */
    @SuppressWarnings("unchecked")
    public <T> In<T> createIn(String tableName, String excelFileName) {
        Class<?> modelType = testUtils.getClassByTablename(tableName);
        return (In<T>) createIn(modelType, excelFileName);
    }

    /**
     * フロー部品の入力オブジェクトを生成します。
     * <p>
     * フロー部品の入力に同一モデル(テーブル)が複数存在する場合は このメソッドを使います。
     * </p>
     *
     * @param <T> データモデルクラス
     * @param modelType データモデルクラス
     * @param excelFileName テストデータ定義シートファイル名(.xlsを除いた値)
     * @return 入力インターフェース
     */
    public <T> In<T> createIn(Class<T> modelType, String excelFileName) {

        String tableName = testUtils.getTablenameByClass(modelType);
        createIndividually = true;
        loadIndividually = true;
        addCreateIn(tableName, excelFileName);

        String path = FlowPartDriverUtils.createInputLocation(driverContext, excelFileName).toPath('/');

        LOG.info("DirectImporterDescription生成:Path=" + excelFileName);

        DirectImporterDescription desc = new DirectImporterDescription(modelType, path);

        String inName;
        int offset = excelFileName.lastIndexOf('/');
        if (offset > -1) {
            inName = excelFileName.substring(offset + 1);
        } else {
            inName = excelFileName;
        }
        return flowDescriptionDriver.createIn(inName, desc);
    }

    /**
     * フロー部品の出力オブジェクトを生成します。
     *
     * @param <T> データモデルクラス
     * @param tableName テーブル名
     * @return 出力インターフェース
     */
    @SuppressWarnings("unchecked")
    public <T> Out<T> createOut(String tableName) {
        Class<?> modelType = testUtils.getClassByTablename(tableName);
        return (Out<T>) createOut(modelType);
    }

    /**
     * フロー部品の出力オブジェクトを生成します。
     *
     * @param <T> データモデルクラス
     * @param modelType データモデルクラス
     * @return 出力インターフェース
     */
    public <T> Out<T> createOut(Class<T> modelType) {

        String tableName = testUtils.getTablenameByClass(modelType);
        addCreateOut(tableName, tableName);
        String path = FlowPartDriverUtils.createOutputLocation(driverContext, tableName).toPath('/');
        LOG.info("DirectExporterDescription生成:Path=" + path);
        ExporterDescription desc = new DirectExporterDescription(modelType, path);
        return flowDescriptionDriver.createOut(tableName, desc);
    }

    /**
     * フロー部品の出力オブジェクトを生成します。
     * <p>
     * フロー部品の出力に同一モデル(テーブル)が複数存在する場合は このメソッドを使います。
     * </p>
     *
     * @param <T> データモデルクラス
     * @param tableName テーブル名
     * @param excelFileName テストデータ定義シートファイル名(.xlsを除いた値)
     * @return 出力インターフェース
     */
    @SuppressWarnings("unchecked")
    public <T> Out<T> createOut(String tableName, String excelFileName) {

        Class<?> modelType = testUtils.getClassByTablename(tableName);
        return (Out<T>) createOut(modelType, excelFileName);

    }

    /**
     * フロー部品の出力オブジェクトを生成します。
     * <p>
     * フロー部品の出力に同一モデル(テーブル)が複数存在する場合は このメソッドを使います。
     * </p>
     *
     * @param <T> データモデルクラス
     * @param modelType データモデルクラス
     * @param excelFileName テストデータ定義シートファイル名(.xlsを除いた値)
     * @return 出力インターフェース
     */
    public <T> Out<T> createOut(Class<T> modelType, String excelFileName) {

        String tableName = testUtils.getTablenameByClass(modelType);
        loadIndividually = true;
        addCreateOut(tableName, excelFileName);

        String path = FlowPartDriverUtils.createOutputLocation(driverContext, excelFileName).toPath('/');

        LOG.info("DirectExporterDescription生成:Path=" + excelFileName);

        DirectExporterDescription desc = new DirectExporterDescription(modelType, path);

        String outName;
        int offset = excelFileName.lastIndexOf(System.getProperty("file.separator"));
        if (offset > -1) {
            outName = excelFileName.substring(offset + 1);
        } else {
            outName = excelFileName;
        }
        return flowDescriptionDriver.createOut(outName, desc);
    }

    private void addCreateIn(String tableName, String fileName) {
        List<String> fileListPerTable = createInMap.get(tableName);
        if (fileListPerTable == null) {
            fileListPerTable = new ArrayList<String>();
            createInMap.put(tableName, fileListPerTable);
        }
        fileListPerTable.add(fileName);
    }

    private void addCreateOut(String tableName, String fileName) {
        List<String> fileListPerTable = createOutMap.get(tableName);
        if (fileListPerTable == null) {
            fileListPerTable = new ArrayList<String>();
            createOutMap.put(tableName, fileListPerTable);
        }
        fileListPerTable.add(fileName);
    }

    private void createAllInput() {
        for (String table : testUtils.getTablenames()) {
            createInput(table, table);
        }
    }

    private void prepareIndividually() {
        for (Map.Entry<String, List<String>> entry : createInMap.entrySet()) {
            String tablename = entry.getKey();
            List<String> fileList = entry.getValue();
            for (String excelFileName : fileList) {
                List<File> inFileList = new ArrayList<File>();
                if (testDataDir != null) {
                    inFileList.add(new File(testDataDir, excelFileName + ".xls"));
                } else {
                    for (File file : testDataFileList) {
                        if (file.getPath().endsWith(excelFileName + ".xls")) {
                            inFileList.add(file);
                            break;
                        }
                    }
                }
                try {
                    testUtils = new TestUtils(inFileList);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                createInput(tablename, excelFileName);
            }
        }
    }

    private void createInput(String tablename, String excelFileName) {
        FileSystem fs = null;
        try {
            Configuration conf = ConfigurationFactory.getDefault().newInstance();
            fs = FileSystem.get(conf);
            URI inputPath = new URI(computeInputPath(fs, excelFileName));
            LOG.info("テストデータを配置します:Path=" + inputPath);
            testUtils.storeToTemporary(tablename, conf, new Path(inputPath));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    private void loadAndInspectResults() throws IOException {
        for (String table : testUtils.getTablenames()) {
            loadResult(table, table);
        }
        if (!testUtils.inspect()) {
            Assert.fail(testUtils.getCauseMessage());
        }
    }

    private void loadAndInspectResultsIndividually() throws IOException {
        for (Map.Entry<String, List<String>> entry : createOutMap.entrySet()) {
            String tablename = entry.getKey();
            List<String> fileList = entry.getValue();
            for (String excelFileName : fileList) {
                List<File> outFileList = new ArrayList<File>();
                if (testDataDir != null) {
                    outFileList.add(new File(testDataDir, excelFileName + ".xls"));
                } else {
                    for (File file : testDataFileList) {
                        if (file.getPath().endsWith(excelFileName + ".xls")) {
                            outFileList.add(file);
                            break;
                        }
                    }
                }
                try {
                    testUtils = new TestUtils(outFileList);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                loadResult(tablename, excelFileName);
                if (!testUtils.inspect()) {
                    Assert.fail(testUtils.getCauseMessage());
                    return;
                }
            }
        }
    }

    private void loadResult(String tablename, String excelFileName) throws IOException {
        Configuration conf = ConfigurationFactory.getDefault().newInstance();
        FileSystem fs = FileSystem.get(conf);
        FileStatus[] status = fs.globStatus(new Path(computeOutputPath(fs, excelFileName)));
        Path[] listedPaths = FileUtil.stat2Paths(status);
        for (Path path : listedPaths) {
            if (isSystemFile(path)) {
                continue;
            }
            LOG.info("出力結果をロードします:Path=" + path);
            testUtils.loadFromTemporary(tablename, conf, path);
        }
    }

    private boolean isSystemFile(Path path) {
        assert path != null;
        String name = path.getName();
        return name.equals(FileOutputCommitter.SUCCEEDED_FILE_NAME) || name.equals("_logs");
    }

    private String computeInputPath(FileSystem fs, String tableName) {
        Location location = FlowPartDriverUtils.createInputLocation(driverContext, tableName);
        String path = new Path(fs.getWorkingDirectory(), location.toPath('/')).toString();
        return resolvePath(path);
    }

    private String computeOutputPath(FileSystem fs, String tableName) {
        Location location = FlowPartDriverUtils.createOutputLocation(driverContext, tableName);
        String path = new Path(fs.getWorkingDirectory(), location.toPath('/')).toString();
        return resolvePath(path);
    }

    private String resolvePath(String path) {
        assert path != null;
        Map<String, String> arguments = driverContext.getArguments();
        VariableTable variables = new VariableTable();
        variables.defineVariables(arguments);
        return variables.parse(path, false);
    }
}
TOP

Related Classes of com.asakusafw.testdriver.FlowPartTestDriver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.