content: package com.aliyun.dataworks.common.spec.domain.dw.codemodel;
  
  import java.util.Collections;
  import java.util.List;
  import java.util.Map;
  
  import com.alibaba.fastjson2.JSON;
  import com.alibaba.fastjson2.JSONWriter.Feature;
  
  import com.aliyun.dataworks.common.spec.SpecUtil;
  import com.aliyun.dataworks.common.spec.domain.DataWorksWorkflowSpec;
  import com.aliyun.dataworks.common.spec.domain.Spec;
  import com.aliyun.dataworks.common.spec.domain.Specification;
  import com.aliyun.dataworks.common.spec.domain.dw.nodemodel.DataWorksNodeAdapter.Context;
  import com.aliyun.dataworks.common.spec.domain.dw.nodemodel.DataWorksNodeCodeAdapter;
  import com.aliyun.dataworks.common.spec.domain.dw.types.CodeProgramType;
  import com.aliyun.dataworks.common.spec.domain.paiflow.PaiflowParameter;
  import com.aliyun.dataworks.common.spec.domain.paiflow.PaiflowScriptContent;
  import com.aliyun.dataworks.common.spec.domain.paiflow.PaiflowSpec;
  import com.aliyun.dataworks.common.spec.domain.ref.SpecNode;
  import com.aliyun.dataworks.common.spec.domain.ref.SpecScript;
  import com.aliyun.dataworks.common.spec.domain.ref.runtime.SpecScriptRuntime;
  import com.aliyun.dataworks.common.spec.writer.SpecWriterContext;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Maps;
  import lombok.extern.slf4j.Slf4j;
  import org.junit.Assert;
  import org.junit.Test;
  
  /**
   * @author 戒迷
   * @date 2025/2/6
   */
  @Slf4j
  public class PaiflowYamlCodeTest {
  
      @Test
      public void testGetSpec() throws Exception {
          List<String> pipelineManifest = Lists.newArrayList(
              "apiVersion: core/v1\n"
                  + "metadata:\n"
                  + "  provider: \"pai\"\n"
                  + "  version: v1\n"
                  + "  identifier: rag_parse_chunk\n"
                  + "  uuid: 0e53xa4ogoargdj3qv\n"
                  + "  annotations: {}\n"
                  + "  labels: {}\n"
                  + "spec:\n"
                  + "  inputs:\n"
                  + "    artifacts:\n"
                  + "      - name: input_data\n"
                  + "        metadata:\n"
                  + "          type:\n"
                  + "            DataSet:\n"
                  + "              locationType: OSS\n"
                  + "        desc: Input Data\n"
                  + "        required: false\n"
                  + "        repeated: false\n"
                  + "    parameters:\n"
                  + "      - name: role_arn\n"
                  + "        type: String\n"
                  + "        desc: role_arn\n"
                  + "        value: \"\"\n"
                  + "      - name: chunk_size\n"
                  + "        type: Int\n"
                  + "        desc: The maximum number of tokens in a single chunk.\n"
                  + "        value: 1024\n"
                  + "      - name: chunk_overlap\n"
                  + "        type: Int\n"
                  + "        desc: The maximum number of tokens to overlap between chunks.\n"
                  + "        value: 20\n"
                  + "      - name: node_parser_type\n"
                  + "        type: String\n"
                  + "        desc: \"The node parser type to use for chunking. Options: [Token, Sentence,\n"
                  + "          SentenceWindow].\"\n"
                  + "        value: Token\n"
                  + "      - name: training_service_config\n"
                  + "        type: Map\n"
                  + "        desc: Training service config\n"
                  + "        value: \"\"\n"
                  + "      - name: output_data_path\n"
                  + "        type: String\n"
                  + "        desc: oss path\n"
                  + "        value: \"\"\n"
                  + "      - name: concat_row\n"
                  + "        type: Bool\n"
                  + "        desc: Whether to concat rows when reading csv/excel files\n"
                  + "        value: false\n"
                  + "      - name: recursive\n"
                  + "        type: Bool\n"
                  + "        desc: Whether to recursively parse the files in the directory.\n"
                  + "        value: true\n"
                  + "      - name: target_index\n"
                  + "        type: String\n"
                  + "        desc: The ID of the index (Dataset, DataType=INDEX) that the chunks will be\n"
                  + "          indexed to\n"
                  + "        value: \"\"\n"
                  + "      - name: execution\n"
                  + "        type: Map\n"
                  + "  outputs:\n"
                  + "    artifacts:\n"
                  + "      - name: output_data\n"
                  + "        metadata:\n"
                  + "          type:\n"
                  + "            DataSet:\n"
                  + "              locationType: OSS\n"
                  + "        desc: Output Data\n"
                  + "        value:\n"
                  + "          location:\n"
                  + "            key: \"{{inputs.parameters.output_data_path}}\"\n"
                  + "        required: false\n"
                  + "        repeated: false\n"
                  + "    parameters: []\n"
                  + "  arguments:\n"
                  + "    artifacts: []\n"
                  + "    parameters: []\n"
                  + "  dependencies: []\n"
                  + "  container:\n"
                  + "    image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/max-compute-executor:v20241210134900\n"
                  + "    command:\n"
                  + "      - bash\n"
                  + "      - /paiflow-bin/start.sh\n"
                  + "    envs: {}\n"
                  + "    volumeMounts:\n"
                  + "      - name: pai-volume\n"
                  + "        path: /pai\n"
                  + "  initContainers:\n"
                  + "    - image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/paiflow-init:v1.0.0\n"
                  + "      command:\n"
                  + "        - /bin/sh\n"
                  + "        - -c\n"
                  + "        - paiflow-init download --source\n"
                  + "          'oss://pai-studio-cn-hangzhou-prod/algorithm/pai/rag_parse_chunk/v1/925a31b327ecbd887a1508b630ed1c611aa4abf3/working"
                  + "?endpoint=oss-cn-hangzhou-internal.aliyuncs.com&roleARN=acs:ram::1326689413376250:role/pai-studio-algo-download-role&ownerId"
                  + "=1326689413376250'\n"
                  + "          --destination /pai/main/resource\n"
                  + "      name: paiflow-init\n"
                  + "      envs: {}\n"
                  + "      volumeMounts:\n"
                  + "        - name: pai-volume\n"
                  + "          path: /pai/main\n"
                  + "  sideCarContainers: []\n"
                  + "  pipelines: []\n"
                  + "  volumes:\n"
                  + "    - name: pai-volume\n"
                  + "      emptyDir: {}\n"
              , "apiVersion: core/v1\n"
                  + "metadata:\n"
                  + "  provider: \"pai\"\n"
                  + "  version: v1\n"
                  + "  identifier: tfReadFileData\n"
                  + "  uuid: bzkc4idch46uhs016p\n"
                  + "  annotations: {}\n"
                  + "  labels: {}\n"
                  + "spec:\n"
                  + "  inputs:\n"
                  + "    artifacts: []\n"
                  + "    parameters:\n"
                  + "      - name: arn\n"
                  + "        type: String\n"
                  + "        value: \"\"\n"
                  + "      - name: ossBucket\n"
                  + "        type: String\n"
                  + "        desc: OSS Data Path\n"
                  + "        value: \"\"\n"
                  + "      - name: isModel\n"
                  + "        type: Bool\n"
                  + "        desc: whether the type is model\n"
                  + "        value: false\n"
                  + "      - name: execution\n"
                  + "        type: Map\n"
                  + "        value: \"\"\n"
                  + "  outputs:\n"
                  + "    artifacts:\n"
                  + "      - name: output_1\n"
                  + "        metadata:\n"
                  + "          type:\n"
                  + "            Any:\n"
                  + "              locationType: OSS\n"
                  + "        desc: Output\n"
                  + "        value: {}\n"
                  + "        required: false\n"
                  + "        repeated: false\n"
                  + "    parameters: []\n"
                  + "  arguments:\n"
                  + "    artifacts: []\n"
                  + "    parameters: []\n"
                  + "  dependencies: []\n"
                  + "  container:\n"
                  + "    image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/max-compute-executor:v20240903202600\n"
                  + "    command:\n"
                  + "      - bash\n"
                  + "      - /paiflow-bin/start.sh\n"
                  + "    envs: {}\n"
                  + "    volumeMounts:\n"
                  + "      - name: pai-volume\n"
                  + "        path: /pai\n"
                  + "  initContainers:\n"
                  + "    - image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/paiflow-init:v1.0.0\n"
                  + "      command:\n"
                  + "        - /bin/sh\n"
                  + "        - -c\n"
                  + "        - paiflow-init download --source\n"
                  + "          'oss://pai-studio-cn-hangzhou-prod/algorithm/pai/tfReadFileData/v1/3696209301bde44d516ed39eaf2f0c300370d6b0/working"
                  + "?endpoint=oss-cn-hangzhou-internal.aliyuncs.com&roleARN=acs:ram::1326689413376250:role/pai-studio-algo-download-role&ownerId"
                  + "=1326689413376250'\n"
                  + "          --destination /pai/main/resource\n"
                  + "      name: paiflow-init\n"
                  + "      envs: {}\n"
                  + "      volumeMounts:\n"
                  + "        - name: pai-volume\n"
                  + "          path: /pai/main\n"
                  + "  sideCarContainers: []\n"
                  + "  pipelines: []\n"
                  + "  volumes:\n"
                  + "    - name: pai-volume\n"
                  + "      emptyDir: {}\n"
              , "apiVersion: core/v1\n"
                  + "metadata:\n"
                  + "  provider: \"pai\"\n"
                  + "  version: v1\n"
                  + "  identifier: rag_sync_index\n"
                  + "  uuid: k9wbjh70610s550m8w\n"
                  + "  annotations: {}\n"
                  + "  labels: {}\n"
                  + "spec:\n"
                  + "  inputs:\n"
                  + "    artifacts:\n"
                  + "      - name: input_data\n"
                  + "        metadata:\n"
                  + "          type:\n"
                  + "            DataSet:\n"
                  + "              locationType: OSS\n"
                  + "        desc: Input Data\n"
                  + "        required: false\n"
                  + "        repeated: false\n"
                  + "    parameters:\n"
                  + "      - name: role_arn\n"
                  + "        type: String\n"
                  + "        desc: role_arn\n"
                  + "        value: \"\"\n"
                  + "      - name: target_index\n"
                  + "        type: String\n"
                  + "        desc: The ID of the registered index in PAI (Dataset, DataType=INDEX).\n"
                  + "      - name: training_service_config\n"
                  + "        type: Map\n"
                  + "        desc: Training service config\n"
                  + "        value: \"\"\n"
                  + "      - name: execution\n"
                  + "        type: Map\n"
                  + "  outputs:\n"
                  + "    artifacts:\n"
                  + "      - name: output_data\n"
                  + "        metadata:\n"
                  + "          type:\n"
                  + "            DataSet:\n"
                  + "              locationType: OSS\n"
                  + "        desc: Output Data\n"
                  + "        value: {}\n"
                  + "        required: false\n"
                  + "        repeated: false\n"
                  + "    parameters: []\n"
                  + "  arguments:\n"
                  + "    artifacts: []\n"
                  + "    parameters: []\n"
                  + "  dependencies: []\n"
                  + "  container:\n"
                  + "    image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/max-compute-executor:v20241210134900\n"
                  + "    command:\n"
                  + "      - bash\n"
                  + "      - /paiflow-bin/start.sh\n"
                  + "    envs: {}\n"
                  + "    volumeMounts:\n"
                  + "      - name: pai-volume\n"
                  + "        path: /pai\n"
                  + "  initContainers:\n"
                  + "    - image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/paiflow-init:v1.0.0\n"
                  + "      command:\n"
                  + "        - /bin/sh\n"
                  + "        - -c\n"
                  + "        - paiflow-init download --source\n"
                  + "          'oss://pai-studio-cn-hangzhou-prod/algorithm/pai/rag_sync_index/v1/afb415fb780f5cd50ca65d91b0e4d90e43972afd/working"
                  + "?endpoint=oss-cn-hangzhou-internal.aliyuncs.com&roleARN=acs:ram::1326689413376250:role/pai-studio-algo-download-role&ownerId"
                  + "=1326689413376250'\n"
                  + "          --destination /pai/main/resource\n"
                  + "      name: paiflow-init\n"
                  + "      envs: {}\n"
                  + "      volumeMounts:\n"
                  + "        - name: pai-volume\n"
                  + "          path: /pai/main\n"
                  + "  sideCarContainers: []\n"
                  + "  pipelines: []\n"
                  + "  volumes:\n"
                  + "    - name: pai-volume\n"
                  + "      emptyDir: {}\n"
          );
          String paiflowYaml = "computeResource:\n"
              + "  DLC,Optional: execution_dlc_optional\n"
              + "connectionType: dlc\n"
              + "paraValue: --paiflow_endpoint=paiflow-pre.cn-hangzhou.aliyuncs.com --ai_workspace_endpoint=aiworkspace-pre.cn-hangzhou.aliyuncs.com "
              + "--region=cn-hangzhou\n"
              + "paiflowPipeline:\n"
              + "  apiVersion: core/v1\n"
              + "  metadata:\n"
              + "    identifier: rag_sync_index\n"
              + "    version: v1\n"
              + "  spec:\n"
              + "    inputs:\n"
              + "      parameters:\n"
              + "      - name: role_arn\n"
              + "        type: String\n"
              + "        value: \\\"\\\"\n"
              + "      - name: is_model\n"
              + "        type: Bool\n"
              + "        value: false\n"
              + "      - name: oss_bucket\n"
              + "        type: String\n"
              + "        value: \\\"\\\"\n"
              + "      - name: chunk_overlap\n"
              + "        type: Int\n"
              + "        value: 20\n"
              + "      - name: chunk_size\n"
              + "        type: Int\n"
              + "        value: 1024\n"
              + "      - name: training_service_config\n"
              + "        type: Map\n"
              + "      - name: output_data_path\n"
              + "        type: String\n"
              + "      - name: execution\n"
              + "        type: Map\n"
              + "        value: {}\n"
              + "      - name: node_parser_type\n"
              + "        type: String\n"
              + "        value: Token\n"
              + "      - name: concat_row\n"
              + "        type: Bool\n"
              + "        value: false\n"
              + "      - name: recursive\n"
              + "        type: Bool\n"
              + "        value: true\n"
              + "      - name: create_new_version\n"
              + "        type: Bool\n"
              + "        value: false\n"
              + "      - name: target_index\n"
              + "        type: String\n"
              + "        value: \\\"\\\"\n"
              + "      - name: target_index_with_version\n"
              + "        type: Map\n"
              + "        value: {}\n"
              + "      - name: embedding_batch_size\n"
              + "        type: Int\n"
              + "        value: 8\n"
              + "    outputs:\n"
              + "      artifacts:\n"
              + "      - from: '{{pipelines.rag-sync-index.outputs.artifacts.output_data}}'\n"
              + "        metadata:\n"
              + "          type:\n"
              + "            DataSet:\n"
              + "              locationType: OSS\n"
              + "        name: output_data\n"
              + "        required: false\n"
              + "      parameters: []\n"
              + "    pipelines:\n"
              + "    - metadata:\n"
              + "        identifier: tfReadFileData\n"
              + "        name: read-oss-file\n"
              + "        provider: pai\n"
              + "        version: v1\n"
              + "      spec:\n"
              + "        arguments:\n"
              + "          parameters:\n"
              + "          - from: '{{inputs.parameters.role_arn}}'\n"
              + "            name: arn\n"
              + "          - from: '{{inputs.parameters.is_model}}'\n"
              + "            name: isModel\n"
              + "          - from: '{{inputs.parameters.execution}}'\n"
              + "            name: execution\n"
              + "          - from: '{{inputs.parameters.oss_bucket}}'\n"
              + "            name: ossBucket\n"
              + "    - metadata:\n"
              + "        identifier: rag_parse_chunk\n"
              + "        name: rag-parse-chunk\n"
              + "        provider: pai\n"
              + "        version: v1\n"
              + "      spec:\n"
              + "        arguments:\n"
              + "          artifacts:\n"
              + "          - from: '{{pipelines.read-oss-file.outputs.artifacts.output_1}}'\n"
              + "            name: input_data\n"
              + "          parameters:\n"
              + "          - from: '{{inputs.parameters.role_arn}}'\n"
              + "            name: role_arn\n"
              + "          - from: '{{inputs.parameters.chunk_size}}'\n"
              + "            name: chunk_size\n"
              + "          - from: '{{inputs.parameters.chunk_overlap}}'\n"
              + "            name: chunk_overlap\n"
              + "          - from: '{{inputs.parameters.node_parser_type}}'\n"
              + "            name: node_parser_type\n"
              + "          - from: '{{inputs.parameters.training_service_config}}'\n"
              + "            name: training_service_config\n"
              + "          - from: '{{inputs.parameters.concat_row}}'\n"
              + "            name: concat_row\n"
              + "          - from: '{{inputs.parameters.output_data_path}}'\n"
              + "            name: output_data_path\n"
              + "          - from: '{{inputs.parameters.recursive}}'\n"
              + "            name: recursive\n"
              + "          - from: '{{inputs.parameters.create_new_version}}'\n"
              + "            name: create_new_version\n"
              + "          - from: '{{inputs.parameters.target_index}}'\n"
              + "            name: target_index\n"
              + "          - from: '{{inputs.parameters.target_index_with_version}}'\n"
              + "            name: target_index_with_version\n"
              + "          - from: '{{inputs.parameters.execution}}'\n"
              + "            name: execution\n"
              + "        dependencies:\n"
              + "        - read-oss-file\n"
              + "    - metadata:\n"
              + "        identifier: rag_sync_index\n"
              + "        name: rag-sync-index\n"
              + "        provider: pai\n"
              + "        version: v1\n"
              + "      spec:\n"
              + "        arguments:\n"
              + "          artifacts:\n"
              + "          - from: '{{pipelines.rag-parse-chunk.outputs.artifacts.output_data}}'\n"
              + "            name: input_data\n"
              + "          parameters:\n"
              + "          - from: '{{inputs.parameters.role_arn}}'\n"
              + "            name: role_arn\n"
              + "          - from: '{{inputs.parameters.create_new_version}}'\n"
              + "            name: create_new_version\n"
              + "          - from: '{{inputs.parameters.target_index}}'\n"
              + "            name: target_index\n"
              + "          - from: '{{inputs.parameters.target_index_with_version}}'\n"
              + "            name: target_index_with_version\n"
              + "          - from: '{{inputs.parameters.training_service_config}}'\n"
              + "            name: training_service_config\n"
              + "          - from: '{{inputs.parameters.execution}}'\n"
              + "            name: execution\n"
              + "          - from: '{{inputs.parameters.embedding_batch_size}}'\n"
              + "            name: embedding_batch_size\n"
              + "        dependencies:\n"
              + "        - rag-parse-chunk\n"
              + "paiflowArguments:\n"
              + "  arguments:\n"
              + "    parameters:\n"
              + "    - name: oss_bucket\n"
              + "      value: oss://langstudio.oss-cn-hangzhou-internal.aliyuncs.com/demo/datasources/fintech/new/\n"
              + "    - name: chunk_size\n"
              + "      value: 1024\n"
              + "    - name: chunk_overlap\n"
              + "      value: 20\n"
              + "    - name: node_parser_type\n"
              + "      value: Sentence\n"
              + "    - name: training_service_config\n"
              + "      value:\n"
              + "        ecs_count: 1\n"
              + "        ecs_spec: ecs.c6.large\n"
              + "        resourceId: public-cluster\n"
              + "        userVpc:\n"
              + "          defaultRoute: eth0\n"
              + "          vpcId: vpc-bp1s5c5wq2k1mn7ijshik\n"
              + "          switchId: vsw-bp1ygzk1u3qp5d4p4o6rr\n"
              + "          securityGroupId: sg-bp12bvw84r9aubravzwm\n"
              + "        maxRunningTimeoutInSeconds: 86400\n"
              + "    - name: execution\n"
              + "      value: {}\n"
              + "    - name: output_data_path\n"
              + "      value: oss://langstudio.oss-cn-hangzhou-internal.aliyuncs.com/demo/artifacts/dening01/\n"
              + "    - name: create_new_version\n"
              + "      value: false\n"
              + "    - name: target_index_with_version\n"
              + "      value:\n"
              + "        datasetId: d-hi912wf9s4i49ix115\n"
              + "        versionId: v1";
  
          log.info("paiflow yaml:{}", paiflowYaml);
          CodeModel<Code> m = CodeModelFactory.getCodeModel(CodeProgramType.PAI_FLOW.getName(), paiflowYaml);
  
          Specification<DataWorksWorkflowSpec> spec = ((PaiflowYamlCode)m.getCodeModel()).getSpec(pipelineManifest);
          Object json = SpecUtil.write(spec, new SpecWriterContext());
          String specString = JSON.toJSONString(json, Feature.PrettyFormat);
          log.info("spec: {}", specString);
  
          DataWorksWorkflowSpec specPaiflow = spec.getSpec();
          Assert.assertNotNull(specPaiflow);
          List<SpecNode> nodes = specPaiflow.getNodes();
          Assert.assertEquals(3, nodes.size());
          SpecNode specNode0 = nodes.get(0);
          Assert.assertEquals("read_oss_file", specNode0.getName());
  
          SpecNode specNode1 = nodes.get(1);
          Assert.assertEquals("rag_parse_chunk", specNode1.getName());
  
          SpecNode specNode2 = nodes.get(2);
          Assert.assertEquals("rag_sync_index", specNode2.getName());
  
          Specification<Spec> specSpecification = SpecUtil.parseToDomain(specString);
          Assert.assertNotNull(specSpecification);
      }
  
      @Test
      public void testGetSpecTemplate() {
          String paiflowYaml = "apiVersion: core/v1\n"
              + "metadata:\n"
              + "  provider: \"pai\"\n"
              + "  version: v1\n"
              + "  identifier: tfReadFileData\n"
              + "  uuid: bzkc4idch46uhs016p\n"
              + "  annotations: {}\n"
              + "  labels: {}\n"
              + "spec:\n"
              + "  inputs:\n"
              + "    artifacts: []\n"
              + "    parameters:\n"
              + "      - name: arn\n"
              + "        type: String\n"
              + "        value: \"\"\n"
              + "      - name: ossBucket\n"
              + "        type: String\n"
              + "        desc: OSS Data Path\n"
              + "        value: \"\"\n"
              + "      - name: isModel\n"
              + "        type: Bool\n"
              + "        desc: whether the type is model\n"
              + "        value: false\n"
              + "      - name: execution\n"
              + "        type: Map\n"
              + "        value: \"\"\n"
              + "  outputs:\n"
              + "    artifacts:\n"
              + "      - name: output_1\n"
              + "        metadata:\n"
              + "          type:\n"
              + "            Any:\n"
              + "              locationType: OSS\n"
              + "        desc: Output\n"
              + "        value: {}\n"
              + "        required: false\n"
              + "        repeated: false\n"
              + "    parameters: []\n"
              + "  arguments:\n"
              + "    artifacts: []\n"
              + "    parameters: []\n"
              + "  dependencies: []\n"
              + "  container:\n"
              + "    image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/max-compute-executor:v20240903202600\n"
              + "    command:\n"
              + "      - bash\n"
              + "      - /paiflow-bin/start.sh\n"
              + "    envs: {}\n"
              + "    volumeMounts:\n"
              + "      - name: pai-volume\n"
              + "        path: /pai\n"
              + "  initContainers:\n"
              + "    - image: pai-official-cn-hangzhou-registry-vpc.cn-hangzhou.cr.aliyuncs.com/official/paiflow-init:v1.0.0\n"
              + "      command:\n"
              + "        - /bin/sh\n"
              + "        - -c\n"
              + "        - paiflow-init download --source\n"
              + "          'oss://pai-studio-cn-hangzhou-prod/algorithm/pai/tfReadFileData/v1/3696209301bde44d516ed39eaf2f0c300370d6b0/working"
              + "?endpoint=oss-cn-hangzhou-internal.aliyuncs.com&roleARN=acs:ram::1326689413376250:role/pai-studio-algo-download-role&ownerId"
              + "=1326689413376250'\n"
              + "          --destination /pai/main/resource\n"
              + "      name: paiflow-init\n"
              + "      envs: {}\n"
              + "      volumeMounts:\n"
              + "        - name: pai-volume\n"
              + "          path: /pai/main\n"
              + "  sideCarContainers: []\n"
              + "  pipelines: []\n"
              + "  volumes:\n"
              + "    - name: pai-volume\n"
              + "      emptyDir: {}\n";
  
          PaiflowYamlCode paiflowYamlCode = new PaiflowYamlCode();
          PaiflowScriptContent paiflowScriptContent = new PaiflowScriptContent();
          paiflowScriptContent.setPaiflowPipeline(PaiflowYamlCode.getYaml().loadAs(paiflowYaml, PaiflowSpec.class));
          paiflowYamlCode.setPaiflowScriptContent(paiflowScriptContent);
  
          Specification<DataWorksWorkflowSpec> spec = paiflowYamlCode.getSpec(Collections.singletonList(paiflowYaml));
  
          System.out.println(SpecUtil.writeToSpec(spec));
      }
  
      @Test
      public void testGetContent() {
          String paiflowYaml = "paiflowPipeline:\n"
              + "  apiVersion: \"core/v1\"\n"
              + "  metadata:\n"
              + "    provider: \"pai\"\n"
              + "    version: \"v1\"\n"
              + "    identifier: \"rag_parse_chunk\"\n"
              + "    uuid: \"0e53xa4ogoargdj3qv\"\n"
              + "    annotations: {}\n"
              + "    labels: {}\n"
              + "  spec:\n"
              + "    inputs:\n"
              + "      artifacts:\n"
              + "      - name: \"input_data\"\n"
              + "        metadata:\n"
              + "          type:\n"
              + "            DataSet:\n"
              + "              locationType: \"OSS\"\n"
              + "        desc: \"Input Data\"\n"
              + "        required: false\n"
              + "        repeated: false\n"
              + "      parameters:\n"
              + "      - name: \"role_arn\"\n"
              + "        type: \"String\"\n"
              + "        desc: \"role_arn\"\n"
              + "        value: \"\"\n"
              + "      - name: \"chunk_size\"\n"
              + "        type: \"Int\"\n"
              + "        desc: \"The maximum number of tokens in a single chunk.\"\n"
              + "        value: 1024\n"
              + "      - name: \"chunk_overlap\"\n"
              + "        type: \"Int\"\n"
              + "        desc: \"The maximum number of tokens to overlap between chunks.\"\n"
              + "        value: 20\n"
              + "      - name: \"node_parser_type\"\n"
              + "        type: \"String\"\n"
              + "        desc: \"The node parser type to use for chunking. Options: [Token, Sentence,\\\\\n"
              + "          \\\\ SentenceWindow].\"\n"
              + "        value: \"Token\"\n"
              + "      - name: \"training_service_config\"\n"
              + "        type: \"Map\"\n"
              + "        desc: \"Training service config\"\n"
              + "        value: \"\"\n"
              + "      - name: \"output_data_path\"\n"
              + "        type: \"String\"\n"
              + "        desc: \"oss path\"\n"
              + "        value: \"\"\n"
              + "      - name: \"concat_row\"\n"
              + "        type: \"Bool\"\n"
              + "        desc: \"Whether to concat rows when reading csv/excel files\"\n"
              + "        value: false\n"
              + "      - name: \"recursive\"\n"
              + "        type: \"Bool\"\n"
              + "        desc: \"Whether to recursively parse the files in the directory.\"\n"
              + "        value: true\n"
              + "      - name: \"target_index\"\n"
              + "        type: \"String\"\n"
              + "        desc: \"The ID of the index (Dataset, DataType=INDEX) that the chunks will be\\\\\n"
              + "          \\\\ indexed to\"\n"
              + "        value: \"\"\n"
              + "      - name: \"execution\"\n"
              + "        type: \"Map\"\n"
              + "    outputs:\n"
              + "      artifacts:\n"
              + "      - name: \"output_data\"\n"
              + "        metadata:\n"
              + "          type:\n"
              + "            DataSet:\n"
              + "              locationType: \"OSS\"\n"
              + "        desc: \"Output Data\"\n"
              + "        value:\n"
              + "          location:\n"
              + "            key: \"{{inputs.parameters.output_data_path}}\"\n"
              + "        required: false\n"
              + "        repeated: false\n"
              + "      parameters: []";
  
          SpecNode paiflowNode = new SpecNode();
          SpecScript script = new SpecScript();
          script.setContent(paiflowYaml);
          SpecScriptRuntime runtime = new SpecScriptRuntime();
          PaiflowParameter paiflowParameter1 = new PaiflowParameter();
          paiflowParameter1.setName("chunk_size");
          paiflowParameter1.setValue("1024");
          PaiflowParameter paiflowParameter2 = new PaiflowParameter();
          paiflowParameter2.setName("chunk_overlap");
          paiflowParameter2.setValue("20");
          Map<String, Object> paiflowConfig = Maps.newHashMap();
          paiflowConfig.put(PaiflowYamlCode.PAIFLOW_CONF_KEY_ARGUMENT_PARAMETER, Lists.newArrayList(paiflowParameter1, paiflowParameter2));
          runtime.setPaiflowConf(paiflowConfig);
          runtime.setCommand("PAI_FLOW_RAG_TEXT_PARSE_CHUNK");
          script.setRuntime(runtime);
          paiflowNode.setScript(script);
  
          DataWorksNodeCodeAdapter adapter = new DataWorksNodeCodeAdapter(paiflowNode);
          Assert.assertNotNull(adapter.getCode());
          System.out.println(adapter.getCode());
      }
  
      @Test
      public void testGetPaiflowContent() {
          SpecNode paiflowNode = new SpecNode();
          paiflowNode.setScript(new SpecScript());
          paiflowNode.getScript().setRuntime(new SpecScriptRuntime());
          paiflowNode.getScript().getRuntime().setCommand("PAI_FLOW");
          DataWorksNodeCodeAdapter adapter = new DataWorksNodeCodeAdapter(paiflowNode);
          Assert.assertNotNull(adapter.getCode());
          System.out.println(adapter.getCode());
  
          adapter.setContext(Context.builder().deployToScheduler(true).build());
          Assert.assertNotNull(adapter.getCode());
          System.out.println(adapter.getCode());
  
      }
  }
  
  //Generated with love by TestMe :) Please raise issues & feature requests at: https://weirddev.com/forum#!/testme