def test_run(stc):
    ctor = CScriptableCreator()
    stc_sys = CStcSystem.Instance()
    project = stc_sys.GetObject("Project")
    plLogger = PLLogger.GetLogger("test_run")
    plLogger.LogInfo("start")

    # Create Tags
    tags = project.GetObject("Tags")
    if tags is None:
        tags = ctor.Create("Tags", project)
    assert tags is not None
    trf_mix_tag = ctor.Create("Tag", tags)
    trf_mix_tag.Set('Name', "ttTemplateMix")
    temp_conf_tag = ctor.Create("Tag", tags)
    temp_conf_tag.Set("Name", "ttCreateTemplateConfigCommand")

    # Create Needed Objects/Commands
    trf_mix = ctor.Create("StmTrafficMix", project)
    trf_mix.Set('MixInfo', get_example_mix_info())
    trf_mix.AddObject(trf_mix_tag, RelationType("UserTag"))
    temp_conf_cmd = ctor.CreateCommand(PKG + ".CreateTemplateConfigCommand")
    temp_conf_cmd.AddObject(temp_conf_tag, RelationType("UserTag"))
    iter_cfg_cmd = ctor.CreateCommand(PKG + ".IteratorConfigMixParamsCommand")
    IteratorConfig.get_this_cmd = MagicMock(return_value=iter_cfg_cmd)

    # Parse example mix info
    json_str = get_example_mix_info()
    err_str, json_obj = json_utils.load_json(json_str)
    assert err_str == ""
    table_data = json_obj["components"]
    assert len(table_data) == 2

    # Row 1
    res = IteratorConfig.run(trf_mix.GetObjectHandle(), get_example_tag_data(),
                             "", "", "", "0", "")
    assert res is True

    # Validate CreateTemplateConfigCommand
    row1_str = get_expected_row1_inputJson()
    err_str, row1 = json_utils.load_json(row1_str)
    assert err_str == ""
    assert temp_conf_cmd.Get("StmTemplateMix") == trf_mix.GetObjectHandle()
    assert temp_conf_cmd.Get("InputJson") == json.dumps(row1)
    assert not temp_conf_cmd.Get("AutoExpandTemplate")

    # Row 2
    res = IteratorConfig.run(trf_mix.GetObjectHandle(), get_example_tag_data(),
                             "", "", "", "1", "")
    assert res is True

    # Validate CreateTemplateConfigCommand
    row2_str = get_expected_row2_inputJson()
    err_str, row2 = json_utils.load_json(row2_str)
    assert err_str == ""
    assert temp_conf_cmd.Get("StmTemplateMix") == trf_mix.GetObjectHandle()
    assert temp_conf_cmd.Get("InputJson") == json.dumps(row2)
    assert not temp_conf_cmd.Get("AutoExpandTemplate")
def on_complete(failed_commands):
    plLogger = PLLogger.GetLogger('methodology')
    this_cmd = get_this_cmd()
    ctor = CScriptableCreator()

    # We don't do anything if one of the hierarchy commands failed...
    if failed_commands is not None and len(failed_commands) > 0:
        err_str = 'CreateRouteMixCommand.on_complete(): ' \
            'No additional processing due to child command failure.'
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    mix_hnd = this_cmd.Get("StmTemplateMix")
    hnd_reg = CHandleRegistry.Instance()
    mix = hnd_reg.Find(mix_hnd)
    err_str, mix_info = json_utils.load_json(mix.Get("MixInfo"))
    if err_str != "":
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    if this_cmd.Get('AutoExpandTemplateMix'):
        cmd = ctor.CreateCommand(RPKG + ".ExpandRouteMixCommand")

        # Pass these through to the expand
        cmd.SetCollection("TargetObjectList", this_cmd.GetCollection('TargetObjectList'))
        cmd.SetCollection("TargetObjectTagList", this_cmd.GetCollection('TargetObjectTagList'))

        # New StmTemplateMix object made by our CreateTemplateConfig operations
        cmd.SetCollection("SrcObjectList", [mix_hnd])

        # Not doing a cmd.Set("SrcObjectTagList")... It's unclear when someone would.
        cmd.Set("RouteCount", float(mix_info.get('routeCount', 0)))
        cmd.Execute()

        if cmd.Get("PassFailState") != "PASSED":
            err_str = "Failed to expand RouteMix: " + mix.Get("Name") + \
                " with handle " + str(mix_hnd) + ": " + cmd.Get("Status")
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            cmd.MarkDelete()
            return False

        cmd.MarkDelete()

    err_str, tag_dict = json_utils.load_json(
        this_cmd.Get('GroupCommandTagInfo'))
    if err_str != "":
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False
    mix_utils.on_complete_remove_tags([tag_name for tag_name in tag_dict])

    return True
def test_on_complete_multi_row(stc):
    sequencer = CStcSystem.Instance().GetObject("Sequencer")
    project = CStcSystem.Instance().GetObject("Project")
    ctor = CScriptableCreator()
    plLogger = PLLogger.GetLogger("methodology")
    plLogger.LogInfo("start_test_on_complete_multi_row")

    # Create MixInfo with multiple rows
    err_str, mix_info = json_utils.load_json(get_example_mix_info())
    assert err_str == ""
    components = mix_info["components"]

    # Duplicate row 4x and change weight
    row_template = components[0]
    row_1 = dict.copy(row_template)
    row_1["weight"] = "50.0 %"
    row_2 = dict.copy(row_template)
    row_2["weight"] = "25.0 %"
    row_3 = dict.copy(row_template)
    row_3["weight"] = "15.0 %"
    row_4 = dict.copy(row_template)
    row_4["weight"] = "10.0 %"

    mix_info["components"] = [row_1, row_2, row_3, row_4]
    proto_mix = ctor.Create("StmProtocolMix", project)
    proto_mix.Set("MixInfo", str(json.dumps(mix_info)))
    cmd = ctor.Create(PKG + ".CreateProtocolMixCommand", sequencer)
    cmd.Set("MixInfo", str(mix_info))
    cmd.Set("MixTagName", "test_StmProtoMix_multirows")
    cmd.SetCollection("PortGroupTagList", ["port group tag"])
    cmd.Set("StmTemplateMix", proto_mix.GetObjectHandle())
    cmd.Set("AutoExpandTemplateMix", False)
    CreateProtoMixCmd.get_this_cmd = MagicMock(return_value=cmd)
    CreateProtoMixCmd.on_complete([])

    # Check the MixInfo
    mi = proto_mix.Get("MixInfo")
    err_str, mi_dict = json_utils.load_json(mi)
    assert err_str == ""
    plLogger.LogInfo("mi: " + str(mi))
    plLogger.LogInfo("mi_dict: " + str(mi_dict))
    assert "deviceCount" in mi_dict.keys()
    assert mi_dict["deviceCount"] == 100
    assert "components" in mi_dict.keys()
    assert len(mi_dict["components"]) == 4
    a_row_1 = mi_dict["components"][0]
    assert a_row_1["weight"] == "50.0 %"
    a_row_2 = mi_dict["components"][1]
    assert a_row_2["weight"] == "25.0 %"
    a_row_3 = mi_dict["components"][2]
    assert a_row_3["weight"] == "15.0 %"
    a_row_4 = mi_dict["components"][3]
    assert a_row_4["weight"] == "10.0 %"
def test_on_complete(stc):
    sequencer = CStcSystem.Instance().GetObject("Sequencer")
    project = CStcSystem.Instance().GetObject("Project")
    ctor = CScriptableCreator()
    proto_mix = ctor.Create("StmProtocolMix", project)
    proto_mix.Set("MixInfo", get_example_mix_info())
    cmd = ctor.Create(PKG + ".CreateProtocolMixCommand", sequencer)
    cmd.Set("MixInfo", get_example_mix_info())
    cmd.Set("MixTagName", "test_StmProtoMix")
    cmd.SetCollection("PortGroupTagList", ["port group tag"])
    cmd.Set("StmTemplateMix", proto_mix.GetObjectHandle())
    cmd.Set("AutoExpandTemplateMix", False)
    CreateProtoMixCmd.get_this_cmd = MagicMock(return_value=cmd)
    CreateProtoMixCmd.on_complete([])

    # Check the MixInfo
    mi = proto_mix.Get("MixInfo")
    err_str, mi_dict = json_utils.load_json(mi)
    assert err_str == ""
    assert "deviceCount" in mi_dict.keys()
    assert mi_dict["deviceCount"] == 100
    assert "components" in mi_dict.keys()
    ti_count = 0
    for item in mi_dict["components"]:
        assert "weight" in item.keys()
        assert item["weight"] == "12.1 %"
        assert "devicesPerBlock" in item.keys()
        assert item["devicesPerBlock"] == 0
        assert "baseTemplateFile" in item.keys()
        assert item["baseTemplateFile"] == "IPv4_NoVlan.xml"
        ti_count = ti_count + 1
    assert ti_count == 1
def test_parse_prop_val_data(stc):
    input_string = '''{
        "ParentTagName": "ttIpv4If",
        "ClassName": "Ipv4If",
        "PropertyValueDict": {
            "PrefixLength": ["22", "11"],
            "IfCountPerLowerIf": ["2", "1"]
        }
    }'''

    expected_prop_val1 = {}
    expected_prop_val1["className"] = "Ipv4If"
    expected_prop_val1["tagName"] = "ttIpv4If"
    expected_prop_val1["propertyValueList"] = {}
    expected_prop_val1["propertyValueList"]["PrefixLength"] = "22"
    expected_prop_val1["propertyValueList"]["IfCountPerLowerIf"] = "2"

    expected_prop_val2 = {}
    expected_prop_val2["className"] = "Ipv4If"
    expected_prop_val2["tagName"] = "ttIpv4If"
    expected_prop_val2["propertyValueList"] = {}
    expected_prop_val2["propertyValueList"]["PrefixLength"] = "11"
    expected_prop_val2["propertyValueList"]["IfCountPerLowerIf"] = "1"

    err_str, input_table_data = json_utils.load_json(input_string)
    assert err_str == ""
    # Call parse on the first row
    res1 = process_util.parse_prop_val_data(input_table_data, 0)
    # Call parse on the second row
    res2 = process_util.parse_prop_val_data(input_table_data, 1)

    assert len(res1["propertyValueList"]) == 1
    assert cmp(res1["propertyValueList"][0], expected_prop_val1) == 0
    assert cmp(res2["propertyValueList"][0], expected_prop_val2) == 0
def test_process_functions(stc):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogInfo("begin test_process_functions")
    meta_json = get_sample_2544_json()
    err_str, meta = json_utils.load_json(meta_json)
    assert not err_str
    kv_dict = {"CommandAddressStartValue": "198.18.1.2",
               "CommandAddressStepValue": "0.0.1.0",
               "LeftBgpEnables": ["1", "22", "333"]
               }

    # Run with missing script file
    err_str = RunCmd.process_functions(meta, kv_dict)
    assert err_str == "Failed to find script: RunMethodologyTestCommandTestScript.py"

    # Create the script file and run
    script_filename = meta["processing_functions"][0]["script_filename"]
    script_full_path = write_testscript(script_filename)
    assert script_full_path is not None
    err_str = RunCmd.process_functions(meta, kv_dict)
    assert not err_str
    assert remove_testscript(script_full_path)
    assert "cmd1.addr.1" in kv_dict
    assert kv_dict["cmd1.addr.1"] == "idk"
    assert "CommandAddressStartValue" in kv_dict
    assert kv_dict["CommandAddressStartValue"] == "198.18.1.2"
    assert "CommandAddressStepValue" in kv_dict
    assert kv_dict["CommandAddressStepValue"] == "0.0.1.0"
    return
def get_meta_json_file_dict(json_path):
    plLogger = PLLogger.GetLogger("methodology")
    plLogger.LogDebug("begin.get_meta_json_file_dict.RunMethodologyTestCommand")

    this_cmd = get_this_cmd()
    meta_json = None

    try:
        # Open the json file
        json_string = None
        file_path = os.path.abspath(json_path)
        if not os.path.exists(file_path):
            return None, "File {} does not exist".format(file_path)
        with open(file_path, "r") as jsonFile:
            json_string = jsonFile.read()
        if not json_string:
            return None, "Error reading methodology json file"
    except:
        return None, "Invalid methodology JSON file: {}".format(json_path)

    # Validate against the schema
    res = json_utils.validate_json(json_string, this_cmd.Get("InputJsonSchema"))
    if res != "":
        err_str = "Methodology JSON is invalid or does not conform to the " + "schema: " + res
        return None, err_str

    # Load the json if it passes schema validation
    err_str, meta_json = json_utils.load_json(json_string)
    if err_str != "":
        return None, err_str

    plLogger.LogDebug("end.get_meta_json_file_dict.RunMethodologyTestCommand")
    return meta_json, ""
def test_parse_meta_json_keys_values(stc):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogInfo("begin test_parse_meta_json_keys_values")

    # Valid methodology json
    input_json = get_sample_2544_json()

    attr1 = "CommandAddressStartValue"
    attr2 = "CommandAddressStepValue"
    attr3 = "TrafficDuration"
    attr4 = "ObjectIteratorCommand.ValueList"
    attr5 = "testGuiOnly"

    val1 = "198.18.1.2"
    val2 = "0.0.1.0"
    val3 = "60"
    val4 = ["64", "128", "256", "512", "1024", "1280", "1518"]
    val5 = "10"

    # Load the json
    err_str, json_dict = json_utils.load_json(input_json)
    assert err_str == ""
    assert json_dict is not None

    # Call the parse function
    key_val_dict, gui_key_val_dict = RunCmd.parse_meta_json_keys_values(json_dict)
    assert key_val_dict is not None
    assert gui_key_val_dict == {'testGuiOnly': '10'}
    plLogger.LogInfo("key_val_dict: " + str(key_val_dict))
    assert len(key_val_dict.keys()) == 7

    # Check the keys
    for kv_pair in zip([attr1, attr2, attr3, attr4, attr5], [val1, val2, val3, val4, val5]):
        assert kv_pair[0] in key_val_dict.keys()
        assert key_val_dict[kv_pair[0]] == kv_pair[1]
def get_txml_proc_dicts(txml_root):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogDebug('RunStmTestCaseCommand.get_txml_proc_dicts.begin')
    MetaMan = txml_utils.MetaManager
    input_dict_list = []
    proc_funcs_ele = txml_root.find('.//' + MetaMan.P_PROC_FUNCS)
    if proc_funcs_ele is None:
        return input_dict_list
    for proc_func_ele in proc_funcs_ele:
        if proc_func_ele.tag != MetaMan.P_PROC_DICT:
            plLogger.LogWarn('(get_txml_proc_dicts) Skipping element '
                             + proc_func_ele.tag +
                             ' in the TXML')
            continue

        input_dict = proc_func_ele.get(MetaMan.P_INPUT_DICT)
        if input_dict is not None and input_dict != "":
            # Validate the interface_dict against the schema
            res = json_utils.validate_json(input_dict,
                                           get_datamodel_dict_schema())
            if res != "":
                plLogger.LogError(res)
                return input_dict_list
            err_str, input_json = json_utils.load_json(input_dict)

            # FIXME:
            # Gracefully exit somehow
            if err_str != "":
                plLogger.LogError(err_str)
            input_dict_list.append(input_json)

    plLogger.LogDebug('RunStmTestCaseCommand.get_txml_proc_dicts.end')
    return input_dict_list
def test_on_complete(stc):
    sequencer = CStcSystem.Instance().GetObject("Sequencer")
    project = CStcSystem.Instance().GetObject("Project")
    ctor = CScriptableCreator()
    route_mix = ctor.Create("StmTemplateMix", project)
    route_mix.Set("MixInfo", get_example_table_data())
    cmd = ctor.Create(RPKG + ".CreateRouteMixCommand", sequencer)
    cmd.Set("MixInfo", get_example_table_data())
    cmd.SetCollection("TargetObjectList", [route_mix.GetObjectHandle()])
    cmd.Set("AutoExpandTemplateMix", False)
    cmd.Set("StmTemplateMix", route_mix.GetObjectHandle())

    # Mock get_this_cmd
    gtc_p = patch(RPKG + ".CreateRouteMixCommand.get_this_cmd",
                  new=MagicMock(return_value=cmd))
    gtc_p.start()

    # Call on_complete
    CreateRouteMixCmd.on_complete([])

    # Check the MixInfo
    mi = route_mix.Get("MixInfo")
    err_str, mi_dict = json_utils.load_json(mi)
    assert err_str == ""
    assert mi_dict.get("routeCount", 0) == 1000
    comp_list = mi_dict.get("components", [])
    assert len(comp_list) == 2
    gtc_p.stop()
def test_parse_protocol_list_data(stc):
    input_string = '''{
        "EnableProperty": "Left.CreateProtocolMix.EnableBgp",
        "ParentTagName": "ttBgpRouterConfig",
        "ClassName": "BgpRouterConfig",
        "PropertyValueDict": {
          "IpVersion": ["BLAH", "IPV4"],
          "EnableBfd": ["False", "True"]
        },
        "StmPropertyModifierDict": {
          "AsNum": {
            "Start": ["0", "10"],
            "Step": ["0", "1"]
          },
          "DutAsNum": {
            "Start": ["0", "20"],
            "Step": "1"
          }
        }
      }'''

    expected_prop_val = {}
    expected_prop_val["className"] = "BgpRouterConfig"
    expected_prop_val["tagName"] = "ttBgpRouterConfig"
    expected_prop_val["propertyValueList"] = {}
    expected_prop_val["propertyValueList"]["IpVersion"] = "IPV4"
    expected_prop_val["propertyValueList"]["EnableBfd"] = "True"

    expected_prop_mod1 = {}
    expected_prop_mod1["className"] = "BgpRouterConfig"
    expected_prop_mod1["tagName"] = "ttBgpRouterConfig.AsNum"
    expected_prop_mod1["parentTagName"] = "ttBgpRouterConfig"
    expected_prop_mod1["propertyName"] = "AsNum"
    expected_prop_mod1["propertyValueList"] = {}
    expected_prop_mod1["propertyValueList"]["Start"] = "10"
    expected_prop_mod1["propertyValueList"]["Step"] = "1"

    expected_prop_mod2 = {}
    expected_prop_mod2["className"] = "BgpRouterConfig"
    expected_prop_mod2["tagName"] = "ttBgpRouterConfig.DutAsNum"
    expected_prop_mod2["parentTagName"] = "ttBgpRouterConfig"
    expected_prop_mod2["propertyName"] = "DutAsNum"
    expected_prop_mod2["propertyValueList"] = {}
    expected_prop_mod2["propertyValueList"]["Start"] = "20"
    expected_prop_mod2["propertyValueList"]["Step"] = "1"

    err_str, input_table_data = json_utils.load_json(input_string)
    assert err_str == ""

    # Call parse on the second row
    res = process_util.parse_protocol_data(input_table_data, 1)

    assert res["protocolSrcTag"] == "ttBgpRouterConfig"

    assert len(res["propertyValueList"]) == 1
    assert cmp(res["propertyValueList"][0], expected_prop_val) == 0

    assert len(res["stmPropertyModifierList"]) == 2
    assert expected_prop_mod1 in res["stmPropertyModifierList"]
    assert expected_prop_mod2 in res["stmPropertyModifierList"]
def test_run_the_proc_func(stc):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogInfo("begin test_run_the_proc_func")
    meta_json = get_sample_2544_json()
    err_str, meta = json_utils.load_json(meta_json)
    input = {"addr_start": "198.18.1.2", "addr_step": "0.0.1.0", "bgp_enables": ["1", "2", "3"]}
    pf0 = meta["processing_functions"][0]

    # Run with missing script file
    output_dict, err_str = RunCmd.run_the_proc_func(pf0, input)
    assert err_str == "Failed to find script: RunMethodologyTestCommandTestScript.py"

    # Create the script file with proc function that returns error
    script_filename = meta["processing_functions"][0]["script_filename"]
    script_full_path = write_testscript(script_filename, True)
    assert script_full_path is not None
    output_dict, err_str = RunCmd.run_the_proc_func(pf0, input)
    assert err_str == "External script: RunMethodologyTestCommandTestScript running calc_addr " + \
                      "failed with: Error running calc_addr  Input was: {'bgp_enables': " + \
                      "['1', '2', '3'], 'addr_start': '198.18.1.2', 'addr_step': '0.0.1.0'}"
    assert remove_testscript(script_full_path)

    # Create the script file with valid proc function
    script_full_path = write_testscript(script_filename)
    assert script_full_path is not None
    output_dict, err_str = RunCmd.run_the_proc_func(pf0, input)
    assert not err_str
    assert "addr_next" in output_dict
    assert output_dict["addr_next"] == "idk"
    assert remove_testscript(script_full_path)
    return
def on_complete(failed_commands):
    plLogger = PLLogger.GetLogger("Methodology")
    this_cmd = get_this_cmd()
    ctor = CScriptableCreator()
    hnd_reg = CHandleRegistry.Instance()

    # We don't do anything if one of the hierarchy commands failed...
    if failed_commands is not None and len(failed_commands) > 0:
        err_str = "CreateTrafficMixCommand.on_complete(): " + \
            "No additional processing due to child command failure."
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    mix_hnd = this_cmd.Get("StmTemplateMix")
    mix = hnd_reg.Find(mix_hnd)
    err_str, mix_info = json_utils.load_json(mix.Get("MixInfo"))
    if err_str != "":
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False
    portGroupList = this_cmd.GetCollection("PortGroupTagList")

    # Mix Info has list in same order as created, for Expand
    if (this_cmd.Get("AutoExpandTemplateMix")):
        cmd = ctor.CreateCommand(PKG + ".ExpandProtocolMixCommand")
        cmd.Set("StmTemplateMix", mix_hnd)
        cmd.Set("DeviceCount", int(mix_info["deviceCount"]))
        cmd.SetCollection("PortGroupTagList", portGroupList)
        cmd.Execute()
        if cmd.Get("PassFailState") != "PASSED":
            err_str = "Failed to expand ProtocolMix: " + mix.Get("Name") + \
                " with handle " + str(mix_hnd) + ": " + cmd.Get("Status")
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            cmd.MarkDelete()
            return False
        cmd.MarkDelete()

    err_str, tag_dict = json_utils.load_json(
        this_cmd.Get('GroupCommandTagInfo'))
    if err_str != "":
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
    mix_utils.on_complete_remove_tags([tag_name for tag_name in tag_dict])

    return True
def test_parse_interface_list_data(stc):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogDebug('start.test_parse_interface_list_data')
    input_string = '''{
        "ParentTagName": "ttIpv4If",
        "ClassName": "Ipv4If",
        "PropertyValueDict": {
            "PrefixLength": ["22", "11"],
            "IfCountPerLowerIf": ["2", "1"]
        },
        "StmPropertyModifierDict": {
            "Address": {
                "Start": ["2.2.2.2", "0.0.0.0"],
                "Step": ["0.0.0.1", "0.0.0.0"]
            },
            "Gateway": {
                "Start": ["2.2.2.1", "0.0.0.0"],
                "Step": "0.0.1.0"
            }
        }
    }'''

    expected_prop_val = {}
    expected_prop_val["className"] = "Ipv4If"
    expected_prop_val["tagName"] = "ttIpv4If"
    expected_prop_val["propertyValueList"] = {}
    expected_prop_val["propertyValueList"]["PrefixLength"] = "22"
    expected_prop_val["propertyValueList"]["IfCountPerLowerIf"] = "2"

    expected_prop_mod1 = {}
    expected_prop_mod1["className"] = "Ipv4If"
    expected_prop_mod1["tagName"] = "ttIpv4If.Address"
    expected_prop_mod1["parentTagName"] = "ttIpv4If"
    expected_prop_mod1["propertyName"] = "Address"
    expected_prop_mod1["propertyValueList"] = {}
    expected_prop_mod1["propertyValueList"]["Start"] = "2.2.2.2"
    expected_prop_mod1["propertyValueList"]["Step"] = "0.0.0.1"

    expected_prop_mod2 = {}
    expected_prop_mod2["className"] = "Ipv4If"
    expected_prop_mod2["tagName"] = "ttIpv4If.Gateway"
    expected_prop_mod2["parentTagName"] = "ttIpv4If"
    expected_prop_mod2["propertyName"] = "Gateway"
    expected_prop_mod2["propertyValueList"] = {}
    expected_prop_mod2["propertyValueList"]["Start"] = "2.2.2.1"
    expected_prop_mod2["propertyValueList"]["Step"] = "0.0.1.0"

    err_str, input_table_data = json_utils.load_json(input_string)
    assert err_str == ""
    # Call parse on the first row
    res = process_util.parse_interface_data(input_table_data, 0)

    assert len(res["propertyValueList"]) == 1
    assert cmp(res["propertyValueList"][0], expected_prop_val) == 0

    assert len(res["stmPropertyModifierList"]) == 2
    assert expected_prop_mod1 in res["stmPropertyModifierList"]
    assert expected_prop_mod2 in res["stmPropertyModifierList"]
def on_complete(failed_commands):
    plLogger = PLLogger.GetLogger('Methodology')
    this_cmd = get_this_cmd()
    ctor = CScriptableCreator()

    # We don't do anything if one of the hierarchy commands failed...
    if failed_commands is not None and len(failed_commands) > 0:
        plLogger.LogError('CreateTrafficMixCommand.on_complete(): ' +
                          'No additional processing due to child command failure.')
        return False

    mix_hnd = this_cmd.Get("StmTemplateMix")
    hnd_reg = CHandleRegistry.Instance()
    mix = hnd_reg.Find(mix_hnd)
    err_str, mix_info = json_utils.load_json(mix.Get("MixInfo"))
    if err_str != "":
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    if this_cmd.Get('AutoExpandTemplateMix'):
        cmd = ctor.CreateCommand(TPKG + ".ExpandTrafficMixCommand")
        cmd.Set("StmTemplateMix", mix_hnd)
        cmd.Set("Load", float(mix_info["load"]))
        cmd.Set("LoadUnit", mix_info["loadUnits"])
        cmd.Execute()
        if cmd.Get("PassFailState") != "PASSED":
            err_str = "Failed to expand TrafficMix: " + mix.Get("Name") + \
                " with handle " + str(mix_hnd) + ": " + cmd.Get("Status")
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            cmd.MarkDelete()
            return False

        cmd.MarkDelete()

    err_str, tag_dict = json_utils.load_json(
        this_cmd.Get('GroupCommandTagInfo'))
    if err_str != "":
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False
    mix_utils.on_complete_remove_tags([tag_name for tag_name in tag_dict])

    return True
示例#16
0
def test_load_json():
    t_dict = {}
    t_dict["a"] = 1.0
    t_dict["b"] = "str_value"
    j_str = json.dumps(t_dict)
    # assert type(j_str) == str
    err_str, j_dict = json_utils.load_json(j_str)
    assert err_str == ""
    assert type(j_dict) == dict

    # Type testing of the contents of j_dict
    # is handled in test_dumps.

    # Invalid JSON
    t_dict = {"abc"}
    err_str, j_dict = json_utils.load_json(str(t_dict))
    assert "is not valid JSON." in err_str
    assert j_dict == {}
def get_reduced_meta_info(meta_json_str):
    err, meta_json = json_utils.load_json(meta_json_str,
                                          object_pairs_hook_arg=OrderedDict)
    if err:
        return err, ''

    keys_to_remove = [key for key in meta_json.iterkeys()
                      if key not in ma_consts.METH_INFO_LIST_KEYS]
    for key in keys_to_remove:
        meta_json.pop(key, None)
    return '', json.dumps(meta_json, default=str)
def test_gen_range_modifier_json():
    # Minimal
    mi = ConfModCmd.gen_range_modifier_json("EmulatedDevice", "DeviceCount",
                                            ["10", "20", "30"], "40")
    assert mi != ""
    err_str, act_dict = json_utils.load_json(mi)
    assert err_str == ""
    pv_dict = {}
    pv_dict["start"] = ["10", "20", "30"]
    pv_dict["step"] = "40"
    exp_dict = {}
    exp_dict["objectName"] = "EmulatedDevice"
    exp_dict["propertyName"] = "DeviceCount"
    exp_dict["modifierType"] = "RANGE"
    exp_dict["propertyValueDict"] = pv_dict
    assert act_dict == exp_dict

    # Optional repeat, recycle, targetObjectStep, and reset
    mi = ConfModCmd.gen_range_modifier_json("EmulatedDevice", "DeviceCount",
                                            "10", "20", repeat=30,
                                            recycle=40, target_step="50",
                                            reset=True)
    assert mi != ""
    # res = json_utils.validate_json(
    #     mi, proc_func.get_range_modifier_json_schema())
    # assert res == ""
    err_str, act_dict = json_utils.load_json(mi)
    assert err_str == ""
    pv_dict = {}
    pv_dict["start"] = "10"
    pv_dict["step"] = "20"
    pv_dict["repeat"] = 30
    pv_dict["recycle"] = 40
    pv_dict["targetObjectStep"] = "50"
    pv_dict["resetOnNewTargetObject"] = True
    exp_dict = {}
    exp_dict["objectName"] = "EmulatedDevice"
    exp_dict["propertyName"] = "DeviceCount"
    exp_dict["modifierType"] = "RANGE"
    exp_dict["propertyValueDict"] = pv_dict
    assert act_dict == exp_dict
def test_run_with_tag(stc):
    ctor = CScriptableCreator()
    stc_sys = CStcSystem.Instance()
    proj = stc_sys.GetObject('Project')
    port = ctor.Create('Port', proj)
    seq = stc_sys.GetObject('Sequencer')
    # Create and tag the traffic mix
    traf_mix = ctor.Create('StmTrafficMix', proj)
    traf_mix.Set('MixInfo', mix_info_2_components())
    tag_utils.add_tag_to_object(traf_mix, 'MixTag')

    cmd = ctor.Create(PKG + '.AllocateTrafficMixLoadCommand', seq)
    cmd.Set('StmTrafficMix', traf_mix.GetObjectHandle())

    tmpl_list = []
    sb_list = []

    tmpl_list.append(ctor.Create('StmTemplateConfig', traf_mix))
    sb1 = ctor.Create('StreamBlock', port)
    sb_list.append(sb1)
    tmpl_list[-1].AddObject(sb1, RelationType('GeneratedObject'))

    tmpl_list.append(ctor.Create('StmTemplateConfig', traf_mix))
    sb2 = ctor.Create('StreamBlock', port)
    sb_list.append(sb2)
    tmpl_list[-1].AddObject(sb2, RelationType('GeneratedObject'))

    assert command.run(None, 'MixTag', 4, 'FRAMES_PER_SECOND')

    lp_list = [sb.GetObject('StreamBlockLoadProfile',
                            RelationType('AffiliationStreamBlockLoadProfile'))
               for sb in sb_list]
    load_list = [lp.Get('Load') for lp in lp_list]
    assert [3, 1] == load_list
    gen = port.GetObject("Generator")
    assert gen is not None
    gen_conf = gen.GetObject("GeneratorConfig")
    assert gen_conf is not None
    assert gen_conf.Get('schedulingmode') == 'RATE_BASED'

    roots = traf_mix.Get('MixInfo')
    assert roots
    err_str, root = json_utils.load_json(roots)
    assert err_str == ""
    assert 'loadUnits' in root
    assert root['loadUnits'] == 'FRAMES_PER_SECOND'
    assert 'components' in root
    assert len(root['components']) == 2
    assert 'appliedValue' in root['components'][0]
    assert root['components'][0]['appliedValue'] == 3
    assert 'appliedValue' in root['components'][1]
    assert root['components'][1]['appliedValue'] == 1
def test_run_fraction(stc):
    ctor = CScriptableCreator()
    stc_sys = CStcSystem.Instance()
    proj = stc_sys.GetObject('Project')
    port = ctor.Create('Port', proj)
    seq = stc_sys.GetObject('Sequencer')
    # Create the traffic mix
    traf_mix = ctor.Create('StmTrafficMix', proj)
    traf_mix.Set('MixInfo', mix_info_2_components())

    cmd = ctor.Create(PKG + '.AllocateTrafficMixLoadCommand', seq)
    cmd.Set('StmTrafficMix', traf_mix.GetObjectHandle())

    tmpl_list = []
    sb_list = []

    tmpl_list.append(ctor.Create('StmTemplateConfig', traf_mix))
    sb1 = ctor.Create('StreamBlock', port)
    sb_list.append(sb1)
    tmpl_list[-1].AddObject(sb1, RelationType('GeneratedObject'))

    tmpl_list.append(ctor.Create('StmTemplateConfig', traf_mix))
    sb2 = ctor.Create('StreamBlock', port)
    sb_list.append(sb2)
    tmpl_list[-1].AddObject(sb2, RelationType('GeneratedObject'))

    assert command.run(cmd.Get('StmTrafficMix'), '', 10.0, 'PERCENT_LINE_RATE')

    lp_list = [sb.GetObject('StreamBlockLoadProfile',
                            RelationType('AffiliationStreamBlockLoadProfile'))
               for sb in sb_list]
    load_list = [lp.Get('Load') for lp in lp_list]
    assert [7.5, 2.5] == load_list

    roots = traf_mix.Get('MixInfo')
    assert roots
    err_str, root = json_utils.load_json(roots)
    assert err_str == ""
    assert 'loadUnits' in root
    assert root['loadUnits'] == 'PERCENT_LINE_RATE'
    assert 'components' in root
    assert len(root['components']) == 2
    assert 'appliedValue' in root['components'][0]
    assert root['components'][0]['appliedValue'] == 7.5
    assert 'appliedValue' in root['components'][1]
    assert root['components'][1]['appliedValue'] == 2.5
def test_load_adjust_for_kbps_mbps_load(stc):
    ctor = CScriptableCreator()
    stc_sys = CStcSystem.Instance()
    proj = stc_sys.GetObject('Project')
    port = ctor.Create('Port', proj)
    seq = stc_sys.GetObject('Sequencer')
    # Create the traffic mix
    traf_mix = ctor.Create('StmTrafficMix', proj)
    traf_mix.Set('MixInfo', mix_info_3_components())

    tmpl_list = []
    sb_list = []
    tmpl_list.append(ctor.Create('StmTemplateConfig', traf_mix))
    sb1 = ctor.Create('StreamBlock', port)
    sb_list.append(sb1)
    tmpl_list[-1].AddObject(sb1, RelationType('GeneratedObject'))
    tmpl_list.append(ctor.Create('StmTemplateConfig', traf_mix))
    sb2 = ctor.Create('StreamBlock', port)
    sb_list.append(sb2)
    tmpl_list[-1].AddObject(sb2, RelationType('GeneratedObject'))
    cmd = ctor.Create(PKG + '.AllocateTrafficMixLoadCommand', seq)
    cmd.Set('StmTrafficMix', traf_mix.GetObjectHandle())
    assert command.run(cmd.Get('StmTrafficMix'), '', 0.01, 'KILOBITS_PER_SECOND')

    lp_list = [sb.GetObject('StreamBlockLoadProfile',
                            RelationType('AffiliationStreamBlockLoadProfile'))
               for sb in sb_list]
    load_list = [lp.Get('Load') for lp in lp_list]
    assert [1, 9] == load_list
    load_unit_list = [lp.Get('LoadUnit') for lp in lp_list]
    assert ['BITS_PER_SECOND', 'BITS_PER_SECOND'] == load_unit_list

    mix_info = traf_mix.Get('MixInfo')
    err_str, mix_info = json_utils.load_json(mix_info)
    assert err_str == ""
    mix_info["components"][0]["weight"] = "45.0%"
    mix_info["components"][1]["weight"] = "55.0%"
    mix_info["loadUnits"] = "MEGABITS_PER_SECOND"
    traf_mix.Set('MixInfo', json.dumps(mix_info))
    assert command.run(cmd.Get('StmTrafficMix'), '', 0.01, 'MEGABITS_PER_SECOND')
    load_list = [lp.Get('Load') for lp in lp_list]
    assert [4.5, 5.5] == load_list
    load_unit_list = [lp.Get('LoadUnit') for lp in lp_list]
    assert ['KILOBITS_PER_SECOND', 'KILOBITS_PER_SECOND'] == load_unit_list
def match_modifier_to_obj_and_prop_names(mod_ele, obj_name, prop_name):
    plLogger = PLLogger.GetLogger("methodology")
    plLogger.LogDebug(
        "match_modifier_to_obj_and_prop_names: " + str(mod_ele) + "  " + str(obj_name) + "  " + str(prop_name)
    )
    if mod_ele is None:
        return "Invalid ElementTree element", None
    mod_info = mod_ele.get("ModifierInfo")
    if mod_info is None:
        return "Missing ModifierInfo attribute", None
    res = json_utils.validate_json(mod_info, proc_func.get_range_modifier_json_schema())
    if res != "":
        t_err_str = "Failed to validate ModifierInfo JSON against " + "its schema: " + res
        return t_err_str, None
    err_str, mod_dict = json_utils.load_json(mod_info)
    if err_str != "":
        t_err_str = "Failed to load ModifierInfo JSON: " + err_str
        return t_err_str, None
    plLogger.LogInfo("mod_dict: " + str(mod_dict))
    if obj_name != "":
        mod_obj_name = mod_dict.get("objectName")
        plLogger.LogInfo("mod_obj_name: " + str(mod_obj_name))
        if mod_obj_name == obj_name:
            if prop_name != "":
                mod_prop_name = mod_dict.get("propertyName")
                plLogger.LogInfo("mod_prop_name: " + str(mod_prop_name))
                if mod_prop_name == prop_name:
                    return "", mod_ele
            else:
                # Assume it is what it is as it is tagged
                return "", mod_ele
    elif prop_name != "":
        mod_prop_name = mod_dict.get("propertyName")
        if mod_prop_name == prop_name:
            return "", mod_ele
    else:
        # Assume it is what it is as it is tagged
        return "", mod_ele
    # Didn't match
    return "", None
def validate(TestCaseKey, StmTestCase, MethodologyKey, MethodologyJson, EnableResourceCheck):
    plLogger = PLLogger.GetLogger("methodology")
    plLogger.LogDebug("begin.validate.RunMethodologyTestCommand.")

    if TestCaseKey:
        # Check if test case key exists in installed methodologies
        test_case_handle, err_str = mm_utils.get_test_case_from_key(TestCaseKey)
        return err_str
    elif StmTestCase:
        hnd_reg = CHandleRegistry.Instance()
        test_case = hnd_reg.Find(StmTestCase)
        if test_case is None or not test_case.IsTypeOf("StmTestCase"):
            plLogger.LogError("Was unable to find StmTestCase with handle " + str(StmTestCase) + " in the system.")
            return "Could not find StmTestCase"
    else:
        # Must specify a key and json
        if not MethodologyKey or not MethodologyJson:
            return "Must specify a TestCaseKey, StmTestCase or MethodologyKey and MethodologyJson"

        # Validate against the schema
        this_cmd = get_this_cmd()
        res = json_utils.validate_json(MethodologyJson, this_cmd.Get("InputJsonSchema"))
        if res != "":
            return "Methodology JSON is invalid or does not conform to the schema: " + res

        # Load the json if it passes schema validation
        err_str, meth_json = json_utils.load_json(MethodologyJson)
        if err_str != "":
            return err_str

        # Check the MethodologyKey matches the meth key in the json
        if MethodologyKey != meth_json["methodology_key"]:
            return "Methodology Key does not match the methodology_key in the JSON"

    plLogger.LogDebug("end.validate.RunMethodologyTestCommand")
    return ""
def test_run_pass_in_json(stc):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogInfo("begin test_run")

    stc_sys = CStcSystem.Instance()
    sequencer = stc_sys.GetObject("Sequencer")
    ctor = CScriptableCreator()
    common_data_path = stc_sys.GetApplicationCommonDataPath()

    # Create exposed properties for the ports
    project = stc_sys.GetObject('Project')
    left_tag = tag_utils.get_tag_object('Left_Port_Group')
    ep_cfg = ctor.Create('ExposedConfig', project)
    ep = ctor.Create('ExposedProperty', ep_cfg)
    ep.Set('EPNameId', 'LeftPortGroup')
    ep.Set('EPClassId', 'tag')
    ep.Set('EPPropertyId', 'scriptable.name')
    ep.AddObject(left_tag, RelationType('ScriptableExposedProperty'))

    meth_name = "RFC2544THROUGHPUT_SAMPLE_BASIC"
    test_name = "test_run"

    # Clean up the fake installed methodology (if it exists)
    if os.path.exists(os.path.join(common_data_path,
                                   mgr_const.MM_TEST_METH_DIR,
                                   meth_name)):
        meth_man_utils.methodology_rmdir(meth_name)

    # Create a fake installed methodology
    home_dir = meth_man_utils.get_methodology_home_dir()
    assert home_dir is not None
    meth_dir = meth_man_utils.methodology_mkdir(meth_name)
    assert meth_dir is not None
    test_dir = meth_man_utils.methodology_test_case_mkdir(meth_name, test_name)
    assert test_dir is not None

    # Add a fake sequence file
    seq_file = os.path.join(meth_dir, mgr_const.MM_SEQUENCER_FILE_NAME)
    f = open(seq_file, "w")
    f.write("<?xml version=\"1.0\" encoding=\"windows-1252\"?>")
    f.close()

    # Add a fake TXML file
    meta_file = os.path.join(meth_dir, mgr_const.MM_META_FILE_NAME)
    f = open(meta_file, "w")
    data = UnitTestUtils.gen_test_info_header("unit test meth disp name",
                                              meth_name,
                                              "unit test meth test case",
                                              "")
    data = data + UnitTestUtils.UTU_FOOTER
    f.write(data)
    f.close()

    # Initialize the methodology manager by calling update
    cmd = ctor.CreateCommand(PKG +
                             ".UpdateTestMethodologyManagerCommand")
    cmd.Execute()
    cmd.MarkDelete()

    # meth_man = meth_man_utils.get_meth_manager()
    # assert meth_man
    # test_meth_obj_list = meth_man.GetObjects("StmMethodology")
    # assert len(test_meth_obj_list) > 0

    # test_meth = None
    # for test_meth_obj in test_meth_obj_list:
    #     act_meth_key = test_meth_obj.Get("MethodologyKey")
    #     plLogger.LogDebug("meth_name: " + test_meth_obj.Get("Name"))
    #     plLogger.LogDebug("meth_key: " + test_meth_obj.Get("MethodologyKey"))
    #     if act_meth_key == meth_name:
    #         test_meth = test_meth_obj
    #         break

    # Add MethodologyGroupCommand to the sequencer
    meth_group_cmd = ctor.Create(PKG + ".MethodologyGroupCommand", sequencer)
    sequencer.SetCollection("CommandList", [meth_group_cmd.GetObjectHandle()])
    key_value_json = meth_group_cmd.Get("KeyValueJson")
    assert key_value_json == ""

    cmd = ctor.Create(PKG + ".RunMethodologyTestCommand", sequencer)
    RunCmd.get_this_cmd = MagicMock(return_value=cmd)
    RunCmd.load_config = MagicMock()
    # TODO: set it up so we don't have to mock this function
    RunCmd.set_active_test_case = MagicMock()

    # Call run with all empty
    # res = RunCmd.run("", "", "", "", False)
    # assert not res
    # assert 'MethodologyJson does not conform to the schema' in cmd.Get("Status")
    # assert cmd.Get("OutputTestCaseKey") == ''
    # cmd.Set("Status", '')

    # Call run with invalid meth key
    # res = RunCmd.run("", "", "blah", "", False)
    # assert not res
    # assert 'MethodologyJson does not conform to the schema' in cmd.Get("Status")
    # assert cmd.Get("OutputTestCaseKey") == ''
    # cmd.Set("Status", '')

    # Call run with empty json
    # res = RunCmd.run("", "", meth_name, "", False)
    # assert not res
    # assert 'MethodologyJson does not conform to the schema' in cmd.Get("Status")
    # assert cmd.Get("OutputTestCaseKey") == ''
    # cmd.Set("Status", '')

    # Call run with invalid json
    # res = RunCmd.run("", "", meth_name, "invalid json", False)
    # assert not res
    # assert 'MethodologyJson does not conform to the schema' in cmd.Get("Status")
    # assert cmd.Get("OutputTestCaseKey") == ''
    # cmd.Set("Status", '')

    # Call the run function with valid meth key and json
    res = RunCmd.run("", "", meth_name, get_sample_2544_json_basic(), False)
    assert res
    assert cmd.Get("Status") == ''
    assert cmd.Get("OutputTestCaseKey") == meth_name + '-1'

    # The KeyValueJson should be populated after running the command
    key_value_json = meth_group_cmd.Get("KeyValueJson")
    assert key_value_json != ""
    err_str, key_value_dict = json_utils.load_json(key_value_json)
    assert err_str == ""
    assert key_value_dict is not None

    assert len(key_value_dict.items()) == 1
    assert key_value_dict["AddressStartValue"] == "1.1.1.1"

    # Clean up the fake installed methodology
    if os.path.exists(os.path.join(common_data_path,
                                   mgr_const.MM_TEST_METH_DIR,
                                   meth_name)):
        meth_man_utils.methodology_rmdir(meth_name)
def test_run(stc):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogInfo("begin test_run")

    stc_sys = CStcSystem.Instance()
    sequencer = stc_sys.GetObject("Sequencer")
    ctor = CScriptableCreator()
    common_data_path = stc_sys.GetApplicationCommonDataPath()

    # Create exposed properties for the ports
    project = stc_sys.GetObject('Project')
    left_tag = tag_utils.get_tag_object('Left_Port_Group')
    right_tag = tag_utils.get_tag_object('Right_Port_Group')
    ep_cfg = ctor.Create('ExposedConfig', project)
    ep = ctor.Create('ExposedProperty', ep_cfg)
    ep.Set('EPNameId', 'LeftPortGroup')
    ep.Set('EPClassId', 'tag')
    ep.Set('EPPropertyId', 'scriptable.name')
    ep.AddObject(left_tag, RelationType('ScriptableExposedProperty'))
    ep = ctor.Create('ExposedProperty', ep_cfg)
    ep.Set('EPNameId', 'RightPortGroup')
    ep.Set('EPClassId', 'tag')
    ep.Set('EPPropertyId', 'scriptable.name')
    ep.AddObject(right_tag, RelationType('ScriptableExposedProperty'))

    meth_name = "test_RunMethodologyTestCommand_test_run"
    test_name = "test_run"

    # Clean up the fake installed methodology (if it exists)
    if os.path.exists(os.path.join(common_data_path,
                                   mgr_const.MM_TEST_METH_DIR,
                                   meth_name)):
        meth_man_utils.methodology_rmdir(meth_name)

    # Create a fake installed methodology
    home_dir = meth_man_utils.get_methodology_home_dir()
    assert home_dir is not None
    meth_dir = meth_man_utils.methodology_mkdir(meth_name)
    assert meth_dir is not None
    test_dir = meth_man_utils.methodology_test_case_mkdir(meth_name, test_name)
    assert test_dir is not None

    cmd = ctor.Create(PKG + ".RunMethodologyTestCommand", sequencer)
    RunCmd.get_this_cmd = MagicMock(return_value=cmd)
    RunCmd.load_config = MagicMock()
    # TODO: set it up so we don't have to mock this function
    RunCmd.set_active_test_case = MagicMock()

    # Create a valid JSON file
    json_content = get_sample_2544_json()
    meta_json_file = os.path.join(test_dir, mgr_const.MM_META_JSON_FILE_NAME)
    f = open(meta_json_file, "w")
    f.write(json_content)
    f.close()

    meth_man = stc_sys.GetObject("StmMethodologyManager")
    if meth_man is None:
        meth_man = ctor.Create("StmMethodologyManager", stc_sys)
    assert meth_man
    test_meth = ctor.Create("StmMethodology", meth_man)
    test_meth.Set("MethodologyKey", meth_name)
    test_case = ctor.Create("StmTestCase", test_meth)
    assert test_case is not None
    assert test_case.IsTypeOf("StmTestCase")
    test_case.Set("Path", test_dir)
    test_case.Set("TestCaseKey", test_name)

    # Add MethodologyGroupCommand to the sequencer
    meth_group_cmd = ctor.Create(PKG + ".MethodologyGroupCommand", sequencer)
    sequencer.SetCollection("CommandList", [meth_group_cmd.GetObjectHandle()])
    key_value_json = meth_group_cmd.Get("KeyValueJson")
    assert key_value_json == ""

    # Call the run function with invalid StmTestCase handle
    res = RunCmd.run("", test_meth.GetObjectHandle(), "", "", False)
    assert not res
    assert 'Was unable to find StmTestCase with handle' in cmd.Get("Status")
    cmd.Set("Status", '')

    # Call the run function with missing proc function script file
    res = RunCmd.run("", test_case.GetObjectHandle(), "", "", False)
    assert not res
    assert cmd.Get("Status") == 'Failed to find script: RunMethodologyTestCommandTestScript.py'
    cmd.Set("Status", '')

    # Create the proc function script file
    err_str, meta = json_utils.load_json(json_content)
    assert err_str == ""
    script_filename = meta["processing_functions"][0]["script_filename"]
    script_full_path = write_testscript(script_filename)
    assert script_full_path is not None

    # Call the run function with valid StmTestCaseHandle
    res = RunCmd.run("", test_case.GetObjectHandle(), "", "", False)
    assert res
    assert cmd.Get("Status") == ''

    # The KeyValueJson should be populated after running the command
    key_value_json = meth_group_cmd.Get("KeyValueJson")
    assert key_value_json != ""
    err_str, key_value_dict = json_utils.load_json(key_value_json)
    assert err_str == ""
    assert key_value_dict is not None

    assert len(key_value_dict.items()) == 8
    assert key_value_dict["CommandAddressStartValue"] == "198.18.1.2"
    assert key_value_dict["CommandAddressStepValue"] == "0.0.1.0"
    assert key_value_dict["TrafficDuration"] == "60"
    vlist = key_value_dict["ObjectIteratorCommand.ValueList"]
    assert type(vlist) is list
    sitems = set(vlist) & set(["64", "128", "256", "512", "1024", "1280", "1518"])
    assert len(sitems) == 7
    assert key_value_dict["cmd1.bgp.count"] == "3"

    # Clear out KeyValueJson in the meth group command
    meth_group_cmd.Set("KeyValueJson", "")
    key_value_json = meth_group_cmd.Get("KeyValueJson")
    assert key_value_json == ""

    # Call the run function with invalid test case key
    res = RunCmd.run("InvalidTestCaseKey", 0, "", "", False)
    assert not res
    assert cmd.Get("Status") == 'Test case with key InvalidTestCaseKey not found'
    cmd.Set("Status", '')

    # Call the run function with valid test case key
    res = RunCmd.run(test_name, 0, "", "", False)
    assert res
    assert cmd.Get("Status") == ''

    # The KeyValueJson should be populated after running the command
    key_value_json = meth_group_cmd.Get("KeyValueJson")
    assert key_value_json != ""
    err_str, key_value_dict = json_utils.load_json(key_value_json)
    assert err_str == ""
    assert key_value_dict is not None
    assert len(key_value_dict.items()) == 8

    assert remove_testscript(script_full_path)

    # Clean up the fake installed methodology
    if os.path.exists(os.path.join(common_data_path,
                                   mgr_const.MM_TEST_METH_DIR,
                                   meth_name)):
        meth_man_utils.methodology_rmdir(meth_name)
def test_generate_tagged_ports(stc):
    project = CStcSystem.Instance().GetObject('Project')
    ctor = CScriptableCreator()
    left_tag = tag_utils.get_tag_object('Left_Port_Group')
    right_tag = tag_utils.get_tag_object('Right_Port_Group')
    ep_cfg = ctor.Create('ExposedConfig', project)
    ep = ctor.Create('ExposedProperty', ep_cfg)
    ep.Set('EPNameId', 'LeftPortGroup')
    ep.Set('EPClassId', 'tag')
    ep.Set('EPPropertyId', 'scriptable.name')
    ep.AddObject(left_tag, RelationType('ScriptableExposedProperty'))
    ep = ctor.Create('ExposedProperty', ep_cfg)
    ep.Set('EPNameId', 'RightPortGroup')
    ep.Set('EPClassId', 'tag')
    ep.Set('EPPropertyId', 'scriptable.name')
    ep.AddObject(right_tag, RelationType('ScriptableExposedProperty'))

    # The sample didn't have everything, so this unit test will take the
    # minimum needed
    input_dict_string = '''{
        "port_groups": [
            {
                "prop_id": "LeftPortGroup",
                "name": "Left",
                "bring_online": true,
                "ports": [
                    {
                        "location": "10.10.10.1/1/1"
                    }
                ]
            },
            {
                "prop_id": "RightPortGroup",
                "name": "Right",
                "ports": [
                    {
                        "location": "10.10.10.2/1/1"
                    }
                ]
            }
        ]
    }'''
    err_str, input_dict = json_utils.load_json(input_dict_string)
    assert err_str == ""

    port_hnd_list, offline, err_str = RunCmd.generate_tagged_ports(input_dict)

    assert 2 == len(port_hnd_list)
    assert False is offline
    assert err_str == ""
    hnd_reg = CHandleRegistry.Instance()
    port_list = [hnd_reg.Find(hnd) for hnd in port_hnd_list]
    tag0 = port_list[0].GetObject('Tag', RelationType('UserTag'))
    tag1 = port_list[1].GetObject('Tag', RelationType('UserTag'))
    assert left_tag.GetObjectHandle() == tag0.GetObjectHandle()
    assert port_list[0].Get('Name').startswith('Left 1')
    assert port_list[0].Get('Location') == '//10.10.10.1/1/1'
    assert right_tag.GetObjectHandle() == tag1.GetObjectHandle()
    assert port_list[1].Get('Name').startswith('Right 1')
    assert port_list[1].Get('Location') == '//10.10.10.2/1/1'

    # Test the bring_online parameter
    input_dict_string = '''{
        "port_groups": [
            {
                "prop_id": "LeftPortGroup",
                "name": "Left",
                "bring_online": false,
                "ports": [
                    {
                        "location": "10.10.10.1/1/1"
                    }
                ]
            },
            {
                "prop_id": "RightPortGroup",
                "name": "Right",
                "bring_online": true,
                "ports": [
                    {
                        "location": "10.10.10.2/1/1"
                    }
                ]
            }
        ]
    }'''
    err_str, input_dict = json_utils.load_json(input_dict_string)
    assert err_str == ""

    port_hnd_list, offline, err_str = RunCmd.generate_tagged_ports(input_dict)

    assert 2 == len(port_hnd_list)
    assert True is offline
    assert err_str == ""
def test_parse_meta_json_keys_values_invalid_json(stc):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogInfo("begin test_parse_meta_json_keys_values_invalid_json")

    # No property_groups
    input_json = '''{
        "methodology_key": "RFC2544THROUGHPUT",
        "display_name": "RFC 2544 Throughput Test",
        "version": "1-0-0",
        "feature_ids": [],
        "port_groups": []
    }'''

    # Load the json
    err_str, json_dict = json_utils.load_json(input_json)
    assert err_str == ""
    assert json_dict is not None

    # Call the parse function
    key_val_dict, gui_key_val_dict = RunCmd.parse_meta_json_keys_values(json_dict)
    assert key_val_dict == {}
    assert gui_key_val_dict == {}

    # No test_properties
    input_json = '''{
        "methodology_key": "RFC2544THROUGHPUT",
        "display_name": "RFC 2544 Throughput Test",
        "version": "1-0-0",
        "feature_ids": [],
        "port_groups": [],
        "property_groups": []
    }'''

    # Load the json
    err_str, json_dict = json_utils.load_json(input_json)
    assert err_str == ""
    assert json_dict is not None

    # Call the parse function
    key_val_dict, gui_key_val_dict = RunCmd.parse_meta_json_keys_values(json_dict)
    assert key_val_dict == {}
    assert gui_key_val_dict == {}

    # Missing property_value and empty test_properties
    input_json = '''{
        "methodology_key": "RFC2544THROUGHPUT",
        "display_name": "RFC 2544 Throughput Test",
        "version": "1-0-0",
        "feature_ids": [],
        "port_groups": [],
        "property_groups": [
            {
                "prop_id": "leftEndpointConfig",
                "display_name": "Left Endpoint Addressing",
                "test_properties": [
                    {
                        "prop_id": "CommandAddressStartValue"
                    },
                    {
                        "prop_id": "CommandAddressStepValue",
                        "property_value": "0.0.1.0"
                    }
                ]
            },
            {
                "prop_id": "test",
                "display_name": "Test",
                "test_properties": []
            }
        ]
    }'''

    attr1 = "CommandAddressStepValue"
    val1 = "0.0.1.0"

    # Load the json
    err_str, json_dict = json_utils.load_json(input_json)
    assert err_str == ""
    assert json_dict is not None

    # Call the parse function
    key_val_dict, gui_key_val_dict = RunCmd.parse_meta_json_keys_values(json_dict)
    assert key_val_dict is not None
    assert gui_key_val_dict == {}
    plLogger.LogInfo("key_val_dict: " + str(key_val_dict))
    assert len(key_val_dict.keys()) == 1

    # Check the keys
    for kv_pair in zip([attr1], [str(val1)]):
        assert kv_pair[0] in key_val_dict.keys()
        assert key_val_dict[kv_pair[0]] == kv_pair[1]
def test_run(stc):
    sequencer = CStcSystem.Instance().GetObject('Sequencer')
    project = CStcSystem.Instance().GetObject('Project')
    ctor = CScriptableCreator()
    hnd_reg = CHandleRegistry.Instance()
    cmd = ctor.Create(TPKG + '.CreateTrafficMixCommand', sequencer)

    plLogger = PLLogger.GetLogger('test_CreateTrafficMixCommand.test_run')
    plLogger.LogInfo('start')

    CreateTMix2Cmd.get_this_cmd = MagicMock(return_value=cmd)
    CreateTMix2Cmd.run(mix_info(), 'TheMix', False)

    # Check the created StmTemplateMix
    mix_hnd = cmd.Get('StmTemplateMix')
    mix = hnd_reg.Find(mix_hnd)
    assert mix
    assert mix.Get('MixInfo') == mix_info()

    # Find the tagged commands
    tag_json = cmd.Get('GroupCommandTagInfo')
    assert tag_json != ''
    err_str, tag_dict = json_utils.load_json(tag_json)
    assert err_str == ""

    tagged_obj_list = tag_utils.get_tagged_objects_from_string_names(
        [tag_dict['rowIterator']])
    assert len(tagged_obj_list) == 1
    obj_iter = tagged_obj_list[0]
    assert obj_iter.IsTypeOf(PKG + '.ObjectIteratorCommand')
    assert obj_iter.Get('StepVal') == 1.0
    assert obj_iter.Get('MaxVal') == 0.0
    assert obj_iter.Get('MinVal') == 0.0
    assert obj_iter.Get('IterMode') == 'STEP'
    assert obj_iter.Get('ValueType') == 'RANGE'

    tagged_obj_list = tag_utils.get_tagged_objects_from_string_names(
        [tag_dict['rowConfigurator']])
    assert len(tagged_obj_list) == 1
    config_cmd = tagged_obj_list[0]
    assert config_cmd.IsTypeOf(PKG + '.IteratorConfigMixParamsCommand')
    assert mix_hnd == config_cmd.Get('StmTemplateMix')

    # Check the Tag
    tags = project.GetObject('Tags')
    assert tags
    user_tag_list = tags.GetObjects('Tag')
    assert len(user_tag_list)
    exp_tag = None
    for user_tag in user_tag_list:
        if user_tag.Get('Name') == 'TheMix':
            exp_tag = user_tag
            break
    assert exp_tag
    tag_target = exp_tag.GetObject('StmTemplateMix', RelationType('UserTag', 1))
    assert tag_target
    assert tag_target.GetObjectHandle() == mix.GetObjectHandle()

    tagged_obj_list = tag_utils.get_tagged_objects_from_string_names(
        [tag_dict['templateConfigurator']])
    assert len(tagged_obj_list) == 1
    load_cmd = tagged_obj_list[0]
    assert load_cmd.IsTypeOf(PKG + '.CreateTemplateConfigCommand')
    load_input_mix_hnd = load_cmd.Get('StmTemplateMix')
    assert load_input_mix_hnd == mix.GetObjectHandle()
def run(StmTemplateMix, InputJson, AutoExpandTemplate,
        CopiesPerParent, SrcTagList, TargetTagList):
    plLogger = PLLogger.GetLogger('methodology')
    plLogger.LogDebug("CreateTemplateConfigCommand.run")

    hnd_reg = CHandleRegistry.Instance()
    ctor = CScriptableCreator()
    this_cmd = get_this_cmd()
    project = CStcSystem.Instance().GetObject("Project")

    if InputJson == "":
        err_str = "InputJson is an empty string."
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    # Validate the InputJson against the schema
    res = json_utils.validate_json(InputJson,
                                   this_cmd.Get("InputJsonSchema"))
    if res != "":
        err_str = "InputJson is invalid or does not conform to the " + \
            "schema: " + res
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    if StmTemplateMix != "" and StmTemplateMix != 0:
        mix = hnd_reg.Find(StmTemplateMix)
        if mix is None:
            err_str = "StmTemplateMix with given handle: " + \
                str(StmTemplateMix) + " is invalid."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False
        elif not mix.IsTypeOf("StmTemplateMix"):
            err_str = "Object with given handle: " + \
                str(StmTemplateMix) + " is a " + \
                mix.GetType() + ".  If StmTemplateMix is " + \
                "specified, object must be an StmTemplateMix."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False
        parent = mix
    else:
        parent = project

    template = ctor.Create("StmTemplateConfig", parent)
    this_cmd.Set("StmTemplateConfig", template.GetObjectHandle())

    # Breakdown the json
    err_str, conf_data = json_utils.load_json(InputJson)
    if err_str != "":
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    plLogger.LogDebug("conf_data: " + str(conf_data))

    # Do the load first
    if "baseTemplateFile" not in conf_data.keys():
        plLogger.LogError("InputJson is missing a baseTemplateFile.")
        return False
    xml_file = conf_data["baseTemplateFile"]

    xml_val = xml_utils.load_xml_from_file(xml_file)
    if xml_val is None:
        err_str = "Was unable to load template XML from " + xml_file
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    # Update the prefixes
    tag_prefix = ""
    if ("tagPrefix" in conf_data.keys() and conf_data["tagPrefix"] != ""):
        tag_prefix = conf_data["tagPrefix"]
    plLogger.LogDebug("using tag_prefix: " + tag_prefix)

    xml_val = xml_utils.add_prefix_to_tags(tag_prefix, xml_val)
    template.Set("TemplateXml", xml_val)
    plLogger.LogDebug("conf_data: " + str(conf_data))

    # Iterate over the objects in the array and apply the appropriate
    # template modification.  Order is determined by the list order.
    for mod_data in conf_data.get("modifyList", []):
        plLogger.LogDebug("mod_data: " + str(mod_data))
        plLogger.LogDebug("mod_data.keys(): " + str(mod_data.keys()))
        err_str = ""
        res = True

        # Merge stuff in mergeList
        for merge_data in mod_data.get("mergeList", []):
            res = run_merge(template, tag_prefix, merge_data)
            err_str = "Failed to merge XML into the StmTemplateConfig " + \
                "given JSON specified as: " + str(merge_data)

        # Process objects in the addObjectList
        for obj_data in mod_data.get("addObjectList", []):
            res = run_objectlist(template, tag_prefix, obj_data)
            err_str = "Failed to add object into the StmTemplateConfig " + \
                "given JSON specified as: " + str(obj_data)

        # Modify the stuff in the PropertyValueList
        for prop_set in mod_data.get('propertyValueList', []):
            res = run_modify(template, tag_prefix, prop_set)
            err_str = "Failed to modify properties in the " + \
                "StmTemplateConfig given JSON specified as: " + \
                str(prop_set)

        # Modify the stuff in the StmPropertyModifierList
        for prop_set in mod_data.get("stmPropertyModifierList", []):
            res = run_config_prop_modifier(template, tag_prefix, prop_set)
            err_str = "Failed to add or configure " + \
                "StmPropertyModifier objects in the StmTemplateConfig " + \
                "given JSON specified as: " + str(prop_set)

        # Modify PDUs
        for pdu_mod in mod_data.get("pduModifierList", []):
            res = run_config_pdu(template, tag_prefix, pdu_mod)
            err_str = "Failed to modify PDU data in a streamblock's " + \
                "FrameConfig in the StmTemplateConfig given JSON " + \
                "specified as: " + str(pdu_mod)

        # Modify the stuff in the RelationList
        for rel_mod in mod_data.get("relationList", []):
            res = run_config_relation(template, tag_prefix, rel_mod)
            err_str = "Failed to add or remove a relation in the " + \
                "StmTemplateConfig given JSON specified as " + str(rel_mod)

        if not res:
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

    # Handle Expand if necessary
    if AutoExpandTemplate:
        res = run_expand(template, TargetTagList,
                         SrcTagList, CopiesPerParent)
        if not res:
            err_str = "Failed to expand the StmTemplateConfig."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

    this_cmd.Set("Status", "")
    return True
def run(StmTemplateMix, TagName, DeviceCount, PortGroupTagList):
    # MixInfo JSON:
    # {
    #     "deviceCount": 100,
    #     "components": [
    #         {
    #             "weight": 10.0,
    #             "devicesPerBlock": 0,
    #             "baseTemplateFile": "IPv4_NoVlan.xml"
    #             "appliedValue": 0,
    #         }
    #     ]
    # }
    plLogger = PLLogger.GetLogger("methodology")
    ctor = CScriptableCreator()
    obj_list = []
    this_cmd = get_this_cmd()
    if StmTemplateMix:
        obj_list = CCommandEx.ProcessInputHandleVec("StmTemplateMix",
                                                    [StmTemplateMix])
    if TagName:
        obj_list = obj_list + \
            tag_utils.get_tagged_objects_from_string_names(
                [TagName])
    if len(obj_list) == 0:
        err_str = "Neither StmTemplateMix nor TagName specified a " + \
            "valid StmTemplateMix object."
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    if DeviceCount < 1:
        err_str = "DeviceCount must be at least 1."
        plLogger.LogError(err_str)
        this_cmd.Set("Status", err_str)
        return False

    # Process obj_list to remove duplicates by using
    # a dictionary indexed on object handle.
    obj_dict = {obj.GetObjectHandle(): obj for obj in obj_list}
    for mix in obj_dict.values():
        str_mix_info = mix.Get("MixInfo")
        if str_mix_info == "":
            err_str = "MixInfo is empty"
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        '''
        # Validate the MixInfo
        # mi_schema = CreateProtoMixCmd_get_mix_info_schema()
        # res = json_utils.validate_json(str_mix_info, mi_schema)
        # if res != "":
            # err_str = res
            # plLogger.LogError(err_str)
            # this_cmd.Set("Status", err_str)
            # return False
        '''

        plLogger.LogDebug("string mix_info: " + str_mix_info)
        mix_info = json_utils.load_json(str_mix_info)
        plLogger.LogDebug("mix_info: " + str(mix_info))

        if "components" not in mix_info.keys():
            err_str = "components is missing in MixInfo for " + \
                              "StmProtocolMix: " + mix.Get("Name")
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        component_list = mix_info["components"]
        if len(component_list) == 0:
            err_str = "Could not find any objects in components in " + \
                              "the MixInfo in " + mix.Get("Name")
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        template_list = mix.GetObjects("StmTemplateConfig")
        if len(component_list) != len(template_list):
            err_str = "Number of component elements in the " + \
                              "MixInfo for " + mix.Get("Name") + \
                              " does not match " + \
                              "number of StmTemplateConfig objects."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        # Check the DeviceCount
        if DeviceCount < len(component_list):
            err_str = "Invalid DeviceCount " + str(DeviceCount) + \
                              " specified.  DeviceCount must be at " + \
                              " least " + str(len(component_list))
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        # Process the weight parameter
        static_list = []
        percent_list = []
        use_percent_list = []

        for component in component_list:
            if "weight" not in component.keys():
                err_str = "Missing required weight parameter in " + \
                                  "Component in StmProtocolMix: " + \
                                  mix.Get("Name")
                plLogger.LogError(err_str)
                this_cmd.Set("Status", err_str)
                return False
            weight = component["weight"]
            is_percent, act_val, err_str = weight_ops.parse_weight_string(
                weight)
            if err_str != "":
                plLogger.LogError(err_str)
                this_cmd.Set("Status", err_str)
                return False

            if is_percent:
                static_list.append(0)
                percent_list.append(act_val)
            else:
                static_list.append(act_val)
                percent_list.append(0)
            use_percent_list.append(is_percent)

        total_static_count = sum(static_list)
        total_percent = sum(percent_list)

        plLogger.LogDebug("total_static_count: " + str(total_static_count))
        plLogger.LogDebug("total_percent: " + str(total_percent))

        # Don't allow the aggregate of static counts to exceed the
        # configured total device count...
        if total_static_count > DeviceCount:
            err_str = "Sum total of the static counts (" + \
                str(int(total_static_count)) + ") exceeds the total " + \
                "configured DeviceCount (" + str(DeviceCount) + ")."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        # Don't allow the total percent to exceed 100%
        if total_percent > 100:
            err_str = "Sum total of the weights defined as percentages (" + \
                str(total_percent) + "%) exceeds 100%."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        # Error if there is no DeviceCount left to divide amongst
        # the weighted components (NetworkCount == 0 probably not allowed)
        if total_percent > 0 and total_static_count == DeviceCount:
            err_str = "Not enough total DeviceCount to distribute devices " + \
                "to all components of the mix.  The required total static " + \
                "device count will use up all of the DeviceCount leaving " + \
                "nothing to distribute on the percent-based weighted " + \
                "components."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        # Calculate how much of the DeviceCount is left for the
        # weighted components...
        total_percent_count = DeviceCount - total_static_count

        # Check that each percent-based weighted component can get
        # at least 1 device
        if total_percent_count < sum(use_percent_list):
            err_str = "Not enough total DeviceCount to distribute devices " + \
                "to all components of the mix.  Once the static counts " + \
                "are handled (if any), there aren't enough devices left (" + \
                str(total_percent_count) + ") such that each " + \
                "percent-based mix component will get at least one device."
            plLogger.LogError(err_str)
            this_cmd.Set("Status", err_str)
            return False

        # Calculate the percent weighted counts from the percents...
        weighted_counts = weight_ops.allocate_weighted_list(
            total_percent_count, percent_list, allow_fraction=False)

        # Apply the counts across each component
        # Assume apply in creation order to map components to templates
        i = 0
        final_device_count = 0
        plLogger.LogInfo("weighted_counts: " + str(weighted_counts))
        plLogger.LogInfo("static_list: " + str(static_list))
        for component, template in zip(component_list, template_list):
            act_value = 0.0
            if use_percent_list[i]:
                act_value = weighted_counts[i]
            else:
                act_value = static_list[i]

            # Note what we chose to apply and then apply it...
            component["appliedValue"] = act_value
            final_device_count += act_value
            i = i + 1

            if "devicesPerBlock" not in component.keys():
                err_str = "Missing required devicesPerBlock parameter in " + \
                                  "Component in StmProtocolMix: " + \
                                  mix.Get("Name")
                plLogger.LogError(err_str)
                this_cmd.Set("Status", err_str)
                return False

            dev_per_block = component["devicesPerBlock"]
            plLogger.LogDebug("Template: " + template.Get("Name"))
            plLogger.LogDebug("dev_count: " + str(act_value))
            plLogger.LogDebug("devicesPerBlock: " + str(dev_per_block))

            last_block_count = 0
            if dev_per_block == 0 or dev_per_block > act_value:
                # All devices into one block
                block_dev_count = act_value
                copies_per_parent = 1
            else:
                # (Greedily) Fill device block with number of devices
                # specified by devicesPerBlock.  Last block will have
                # remainder of devices that does not fill a complete block.
                block_dev_count = dev_per_block
                copies_per_parent = int(act_value // dev_per_block)
                last_block_count = int(act_value % dev_per_block)

            if last_block_count > 0:
                copies_per_parent += 1

            plLogger.LogDebug("block_dev_count: " + str(block_dev_count))
            plLogger.LogDebug("copies_per_parent: " + str(copies_per_parent))
            plLogger.LogDebug("last_block_count: " + str(last_block_count))

            # Call ExpandTemplateConfigCommand
            cmd = ctor.CreateCommand(PKG + ".ExpandTemplateCommand")
            cmd.SetCollection("StmTemplateConfigList", [template.GetObjectHandle()])
            cmd.Set("CopiesPerParent", copies_per_parent)
            cmd.SetCollection("TargetTagList", PortGroupTagList)
            cmd.Execute()
            cmd.MarkDelete()

            emul_dev_list = template.GetObjects("emulateddevice", RelationType("GeneratedObject"))
            for emul_dev in emul_dev_list:
                # Last Block has remainder AND last emulateddevice in list
                if (last_block_count > 0) and (emul_dev == emul_dev_list[-1]):
                    emul_dev.Set("DeviceCount", last_block_count)
                else:
                    emul_dev.Set("DeviceCount", block_dev_count)

    mix_info["deviceCount"] = final_device_count

    # Write the MixInfo back to the StmProtocolMix
    plLogger.LogDebug("dumping back into MixInfo: " + 
                      json.dumps(mix_info))
    mix.Set("MixInfo", json.dumps(mix_info))

    return True