Browse Source

start testcase from dialog

refactor
Ulrich 1 year ago
parent
commit
da9e4cfb78
  1. 2
      basic/program.py
  2. 101
      start_dialog.py
  3. 57
      test/test_30step.py
  4. 16
      test_executer.py
  5. 118
      tools/job_const.py
  6. 14
      tools/job_tool.py
  7. 35
      tools/step_tool.py

2
basic/program.py

@ -398,6 +398,8 @@ class Parameter:
print (f"Parameter initialisiert {self.program}")
pardef = job.programDef[CTLG_PARDEF]
for p in pardef:
if p == "testelem":
continue
if len(p) > 1 and not hasattr(self, p):
raise Exception("Parameter {} is not set for {}!".format(p, self.program))

101
start_dialog.py

@ -26,6 +26,7 @@ import basic.constants as B
import tools.job_tool as job_tool
import model.catalog
import tools.job_const as J
import tools.step_tool
PROGRAM_NAME = "start_dialog"
JOB_PROC = "proc"
@ -77,62 +78,75 @@ def getChoice(job, choiselist, description):
if verbose: print("treffer "+str(choiselist))
return choiselist[int(choice) - 1]
def initDialog(job, args={}):
def initDialog(job):
"""
dialog to initialize a child-process
:param job:
:return:
"""
# which process
args = {}
verify = job.getDebugLevel("job_tool")
if JOB_PROC not in args:
args[JOB_PROC] = getChoice(job, J.LIST_PROC, "Welchen Prozess starten")
args[J.MODEL_GRAN] = ""
args[B.PAR_GRAN] = ""
args[B.PAR_USER] = job_tool.getUser()
args[B.PAR_PROJ] = job_tool.getUserProject()
args[B.PAR_STEP] = ""
job.m.logTrace(verify, args[JOB_PROC])
# """
print("JOB_PROC "+args[JOB_PROC])
if args[JOB_PROC] == J.PROC_TP_EXECUTION:
#args[J.MODEL_GRAN] = B.PAR_TESTPLAN
args[B.PAR_STEP] = "1"
args[B.PAR_GRAN] = B.PAR_TESTPLAN
args[B.PAR_STEP] = tools.step_tool.getNextStepID(job, 0, "", args[B.PAR_GRAN])
args[B.PAR_PROGRAM] = J.PROG_TEST_EXECUTER
elif args[JOB_PROC] in [J.PROC_TS_STEPWISE, J.PROC_TS_EXECUTION]:
#args[J.MODEL_GRAN] = B.PAR_TESTSUITE
args[B.PAR_STEP] = "1"
args[B.PAR_GRAN] = B.PAR_TESTSUITE
args[B.PAR_STEP] = tools.step_tool.getNextStepID(job, 0, "", args[B.PAR_GRAN])
if args[JOB_PROC] == J.PROC_TS_EXECUTION:
args[B.PAR_PROGRAM] = J.PROG_TEST_EXECUTER
else:
args[B.PAR_PROGRAM] = J.PROG_TS_INIT
elif args[JOB_PROC] in [J.PROC_TC_STEPWISE, J.PROC_TC_EXECUTION]:
#args[J.MODEL_GRAN] = B.PAR_TESTCASE
args[B.PAR_STEP] = "1"
if args[JOB_PROC] == J.PROC_TC_EXECUTION:
args[B.PAR_PROGRAM] = J.PROG_TEST_EXECUTER
else:
args[B.PAR_PROGRAM] = J.PROG_TC_INIT
# elif args[JOB_PROC] in [J.PROC_TC_STEPWISE, J.PROC_TC_EXECUTION]:
elif args[JOB_PROC] == J.PROC_TC_EXECUTION:
print("JOB_PROC - 111 " + args[JOB_PROC])
args[B.PAR_GRAN] = B.PAR_TESTCASE
args[B.PAR_STEP] = tools.step_tool.getNextStepID(job, 0, "", args[B.PAR_GRAN])
args[B.PAR_PROGRAM] = J.PROG_TEST_EXECUTER
elif args[JOB_PROC] == J.PROC_TC_STEPWISE:
print("JOB_PROC - 116 " + args[JOB_PROC])
args[B.PAR_GRAN] = B.PAR_TESTCASE
args[B.PAR_STEP] = tools.step_tool.getNextStepID(job, 0, "", args[B.PAR_GRAN])
args[B.PAR_PROGRAM] = J.PROG_TC_INIT
elif args[JOB_PROC] == J.PROC_REDO_EXECUTION:
args[B.PAR_PROGRAM] = getChoice(job, J.LIST_TS_PROGS + J.LIST_TC_PROGS,
"Welches Programm starten")
elif args[JOB_PROC] == J.PROC_SINGLE_JOB:
args[B.PAR_PROGRAM] = getChoice(job, J.LIST_SERVICE_PROG, "Welches Programm starten")
else:
args[J.MODEL_GRAN] = ""
args[J.MODEL_GRAN] = ""
args[B.PAR_GRAN] = ""
# args[B.PAR_GRAN] = ""
# """2
catalog = model.catalog.Catalog.getInstance()
setattr(job.par, B.SUBJECT_PROJECT, "TESTPROJ")
programDef = catalog.getValue(job, basic.program.CTLG_NAME, args[B.PAR_PROGRAM], "")
job.m.logTrace(verify, "programdefinition "+str(programDef))
print("programdefinition "+str(programDef))
if verbose: print("programdefinition "+args[B.PAR_PROGRAM]+" "+str(programDef))
for p in programDef[basic.program.CTLG_PARDEF]:
job.m.logTrace(verify, "progCtlog "+p+":")
job.m.logTrace(verify, args)
if verbose: print(" "+p+" "+str(args))
#for p in programDef[basic.program.CTLG_PARDEF]:
print(str(args))
for p in [B.PAR_PROJ, B.PAR_GRAN, B.PAR_APP, J.ARG_TESTELEM, B.PAR_COMP, B.PAR_ENV,
B.PAR_TESTPLAN, B.PAR_TESTSUITE, B.PAR_TESTCASE,
B.PAR_TSTIME, B.PAR_TCTIME, B.PAR_TPTIME, B.PAR_VAR]:
if p in args and len(args[p]) > 0:
if verbose: print("arg: " + p+" "+args[p])
job.m.logDebug(verify, "progArg "+p+" ist "+args[p])
elif programDef[basic.program.CTLG_PARDEF][p] == "args":
continue
if p not in programDef[basic.program.CTLG_PARDEF]:
continue
if programDef[basic.program.CTLG_PARDEF][p] != "args":
args[p] = programDef[basic.program.CTLG_PARDEF][p]
continue
print("+ bearbeite "+p)
if programDef[basic.program.CTLG_PARDEF][p] == "args":
description = ""
job.m.logDebug(verify, "to select "+p)
if p == B.PAR_GRAN:
@ -141,22 +155,21 @@ def initDialog(job, args={}):
elif p == B.PAR_APP:
description = J.CHOICE_APP
choiceList = job_tool.select_application(job, programDef, args[B.PAR_PROJ])
elif p == J.ARG_TESTELEM:
if verbose: print("testelem "+args[B.PAR_GRAN])
if args[B.PAR_GRAN] in [J.GRAN_TP, B.PAR_TESTPLAN]:
description = J.CHOICE_TP
choiceList = job_tool.select_testplan(job, programDef, args)
p = B.PAR_TESTPLAN
elif args[B.PAR_GRAN] in [J.GRAN_TS, B.PAR_TESTSUITE]:
description = J.CHOICE_TS
choiceList = job_tool.select_testsuite(job, programDef, args)
p = B.PAR_TESTSUITE
elif args[B.PAR_GRAN] in [J.GRAN_TC, B.PAR_TESTCASE]:
description = J.CHOICE_TC
choiceList = job_tool.select_testcase(job, programDef, args)
p = B.PAR_TESTCASE
else:
raise Exception("unknown testgranularity "+args[B.PAR_GRAN])
elif p == B.PAR_TESTPLAN or p == J.ARG_TESTELEM and args[B.PAR_GRAN] in [J.GRAN_TP, B.PAR_TESTPLAN]:
description = J.CHOICE_TP
choiceList = job_tool.select_testplan(job, programDef, args)
p = B.PAR_TESTPLAN
if J.ARG_TESTELEM in programDef[basic.program.CTLG_PARDEF]: args[J.ARG_TESTELEM] = p
elif p == B.PAR_TESTSUITE or p == J.ARG_TESTELEM and args[B.PAR_GRAN] in [J.GRAN_TS, B.PAR_TESTSUITE]:
description = J.CHOICE_TS
choiceList = job_tool.select_testsuite(job, programDef, args)
p = B.PAR_TESTSUITE
if J.ARG_TESTELEM in programDef[basic.program.CTLG_PARDEF]: args[J.ARG_TESTELEM] = p
elif p == B.PAR_TESTCASE or p == J.ARG_TESTELEM and args[B.PAR_GRAN] in [J.GRAN_TC, B.PAR_TESTCASE]:
description = J.CHOICE_TC
choiceList = job_tool.select_testcase(job, programDef, args)
p = B.PAR_TESTCASE
if J.ARG_TESTELEM in programDef[basic.program.CTLG_PARDEF]: args[J.ARG_TESTELEM] = p
elif p == B.PAR_COMP:
description = J.CHOICE_ENV
choiceList = job_tool.select_components(job, programDef, args[B.PAR_PROJ], args[B.PAR_APP])
@ -168,26 +181,22 @@ def initDialog(job, args={}):
elif p in [B.PAR_TESTPLAN, B.PAR_TESTSUITE, B.PAR_TESTCASE]:
if args[JOB_PROC] == J.PROC_REDO_EXECUTION:
description = J.CHOICE_ARCHIV
choiceList = job_tool.select_archiv(job, programDef, args[J.MODEL_GRAN], args[B.PAR_APP])
choiceList = job_tool.select_archiv(job, programDef, args[B.PAR_GRAN], args[B.PAR_APP])
else:
args[B.PAR_STEP] = "1"
description = J.CHOICE_SPEC
choiceList = job_tool.select_spec(job, programDef, args[J.MODEL_GRAN], args)
choiceList = job_tool.select_spec(job, programDef, args[B.PAR_GRAN], args)
elif p in [B.PAR_TSTIME, B.PAR_TCTIME] and args[JOB_PROC] in [J.PROC_REDO_EXECUTION]:
description = J.CHOICE_TIME
choiceList = job_tool.select_testtime(job, programDef, args[J.MODEL_GRAN], args)
choiceList = job_tool.select_testtime(job, programDef, args[B.PAR_GRAN], args)
elif p == B.PAR_VAR:
description = J.CHOICE_VARIANT
choiceList = job_tool.select_variant(job, programDef, args[J.MODEL_GRAN], args)
choiceList = job_tool.select_variant(job, programDef, args[B.PAR_GRAN], args)
else:
continue
if choiceList is None:
job.m.logError(verify, "choiceList in None "+p)
args[p] = getChoice(job, choiceList, description)
else:
args[p] = programDef[basic.program.CTLG_PARDEF][p]
job.m.logDebug(verify, "p "+p+" jetzt ")
job.m.logDebug(verify, args[p])
job.m.logDebug(verify, args)
job_tool.write_child_args(job, args)
job_tool.start_child_process(job, args)

57
test/test_30step.py

@ -0,0 +1,57 @@
"""
unit-test for the topic step-execution in step_tool
"""
import unittest
import os
import inspect
import basic.program
import basic.constants as B
import tools.job_const as J
import test.constants as T
import test.testtools
import tools.step_tool
HOME_PATH = T.HOME_PATH
PYTHON_CMD = "python"
#TEST_FUNCTIONS = [ "test_smokeTestcase"]
TEST_FUNCTIONS = ["test_10getNextID"]
PROGRAM_NAME = "unit_tester"
class MyTestCase(unittest.TestCase):
mymsg = "--------------------------------------------------------------"
def test_10getNextID(self):
global mymsg
actfunction = str(inspect.currentframe().f_code.co_name)
cnttest = 0
if actfunction not in TEST_FUNCTIONS:
return
job = test.testtools.getTestJob()
# start-ids,
setattr(job.par, B.PAR_GRAN, B.SUBJECT_TESTCASE)
sid = tools.step_tool.getNextStepID(job, 0, "")
self.assertEqual(J.STEP_INIT_TC, sid)
sid = tools.step_tool.getNextStepID(job, 0, J.STEP_INIT_TC)
self.assertEqual(J.STEP_EXEC_TC1, sid)
self.assertRaises(Exception, tools.step_tool.getNextStepID, job, 0, J.STEP_INIT_TP)
setattr(job.par, B.PAR_GRAN, B.SUBJECT_TESTSUITE)
sid = tools.step_tool.getNextStepID(job, 0, "")
self.assertEqual(J.STEP_INIT_TS, sid)
sid = tools.step_tool.getNextStepID(job, 0, J.STEP_INIT_TS)
self.assertEqual(J.STEP_INIT_TC, sid)
sid = tools.step_tool.getNextStepID(job, 0, J.STEP_INIT_TC)
self.assertEqual(J.STEP_EXEC_TS1, sid)
setattr(job.par, B.PAR_GRAN, B.SUBJECT_TESTPLAN)
sid = tools.step_tool.getNextStepID(job, 0, "")
self.assertEqual(J.STEP_INIT_TP, sid)
sid = tools.step_tool.getNextStepID(job, 0, J.STEP_INIT_TC)
self.assertEqual(J.STEP_EXEC_TS1, sid)
if __name__ == '__main__':
unittest.main()

16
test_executer.py

@ -21,6 +21,7 @@ import tools.job_tool as job_tool
import model.factory
import model.catalog
import tools.job_tool
import tools.step_tool
PROGRAM_NAME = "test_executer"
myjob = None
@ -51,10 +52,11 @@ def startPyJob(job):
raise Exception("Parameter " + B.PAR_STEP + " is missing")
catalog = model.catalog.Catalog.getInstance()
programs = catalog.readDomain("programs", job)
while int(getattr(job.par, B.PAR_STEP, "99")) < 3:
executeStep(job, steps, programs)
snr = int(getattr(job.par, B.PAR_STEP, "99"))
setattr(job.par, B.PAR_STEP, str(snr+1))
stepnr = int(tools.step_tool.mapStepIDtoNr(job, getattr(job.par, B.PAR_STEP), getattr(job.par, B.PAR_GRAN)))
while stepnr < 3:
stepnr = int(tools.step_tool.mapStepIDtoNr(job, getattr(job.par, B.PAR_STEP), getattr(job.par, B.PAR_GRAN)))
executeStep(job, steps, programs, stepnr)
setattr(job.par, B.PAR_STEP, tools.step_tool.getNextStepID(job, stepnr))
if verify: print(" .. steps durchlaufen z58 .. " + getattr(job.par, B.PAR_STEP, "99"))
#setattr(job.par, "testcases", testcases)
if verify: print(" .. testcases z60 .. " + getattr(job.par, "testcases", "9-9"))
@ -65,7 +67,7 @@ def startPyJob(job):
job.m.logDebug("execpt " + traceback.format_exc())
job.m.logDebug("+++++++++++++++++++++++++++++++++++++++++++++")
def executeStep(job, steps, programs):
def executeStep(job, steps, programs, stepnr):
# TODO run over steps - definition ?!
"""
for arg in step["args"]:
@ -88,10 +90,12 @@ def executeStep(job, steps, programs):
pass
"""
verify = True
stepnr_par = int(stepnr)
for k in steps:
step = steps[k]
if verify: print("step " + k + " snr: " + step.stepnr + " =? " + getattr(job.par, B.PAR_STEP))
if int(step.stepnr) != int(getattr(job.par, B.PAR_STEP)):
if int(step.stepnr) != stepnr_par:
# int(getattr(job.par, B.PAR_STEP)):
if verify: print("step " + k + " != snr ")
continue
if step.name in list(programs.keys()):

118
tools/job_const.py

@ -56,29 +56,107 @@ CHOICE_TIME = "Testzeit auswaehlen"
CHOICE_VARIANT = "Testvariante auswaehlen"
# the sequence of a complete testexecution
STEP_INIT_TP = 10
STEP_INIT_TS = 12
STEP_INIT_TC = 14
STEP_EXEC_TS1 = 22
STEP_EXEC_TC1 = 24
STEP_EXEC_TC2 = 26
STEP_EXEC_TS2 = 28
STEP_COLL_TC = 36
STEP_COLL_TS = 38
STEP_COMP_TC = 46
STEP_COMP_TS = 48
STEP_FIN_TC = 56
STEP_FIN_TS = 58
STEP_FIN_TP = 60
STEP_BREAK = 99
STEP_INIT_TP = "10"
STEP_INIT_TS = "12"
STEP_INIT_TC = "14"
STEP_EXEC_TS1 = "22"
STEP_BREAK_AFTER_TC1 = "99"
""" break before exec_tc1 between testcases """
STEP_EXEC_TC1 = "24"
STEP_BREAK_BETWEEN_TC = "98"
""" break between exec_tc1 and exec_tc2 """
STEP_EXEC_TC2 = "26"
STEP_BREAK_BEFORE_TC2 = "97"
""" break after exec_tc2 between testcases """
STEP_EXEC_TS2 = "28"
STEP_COLL_TC = "36"
STEP_COLL_TS = "38"
STEP_COMP_TC = "46"
STEP_COMP_TS = "48"
STEP_FIN_TC = "56"
STEP_FIN_TS = "58"
STEP_FIN_TP = "60"
""" conditional break if basic configured as not full-automatized """
STEPS_TESTPLAN = [ STEP_INIT_TP, STEP_INIT_TS, STEP_INIT_TC,
STEP_EXEC_TS1, STEP_EXEC_TC1, STEP_BREAK, STEP_EXEC_TC2, STEP_EXEC_TS2,
STEPS_DEFINITON = {
STEP_INIT_TP: {
B.SUBJECT_TESTPLAN: 1
},
STEP_INIT_TS: {
B.SUBJECT_TESTPLAN: 2,
B.SUBJECT_TESTSUITE: 1
},
STEP_INIT_TC: {
B.SUBJECT_TESTPLAN: 3,
B.SUBJECT_TESTSUITE: 2,
B.SUBJECT_TESTCASE: 1
},
STEP_EXEC_TS1:{
B.SUBJECT_TESTPLAN: 4,
B.SUBJECT_TESTSUITE: 3
},
STEP_EXEC_TC1: {
B.SUBJECT_TESTPLAN: 5,
B.SUBJECT_TESTSUITE: 4,
B.SUBJECT_TESTCASE: 2
},
STEP_BREAK_AFTER_TC1: {
B.SUBJECT_TESTPLAN: 6,
B.SUBJECT_TESTSUITE: 5
},
STEP_BREAK_BETWEEN_TC: {
B.SUBJECT_TESTPLAN: 7,
B.SUBJECT_TESTSUITE: 6,
B.SUBJECT_TESTCASE: 3
},
STEP_BREAK_BEFORE_TC2: {
B.SUBJECT_TESTPLAN: 8,
B.SUBJECT_TESTSUITE: 7
},
STEP_EXEC_TC2: {
B.SUBJECT_TESTPLAN: 9,
B.SUBJECT_TESTSUITE: 8,
B.SUBJECT_TESTCASE: 4
},
STEP_EXEC_TS2: {
B.SUBJECT_TESTPLAN: 10,
B.SUBJECT_TESTSUITE: 9
},
STEP_COLL_TC: {
B.SUBJECT_TESTPLAN: 11,
B.SUBJECT_TESTSUITE: 10,
B.SUBJECT_TESTCASE: 5
},
STEP_COLL_TS: {
B.SUBJECT_TESTPLAN: 12,
B.SUBJECT_TESTSUITE: 11
},
STEP_COMP_TC: {
B.SUBJECT_TESTPLAN: 13,
B.SUBJECT_TESTSUITE: 12,
B.SUBJECT_TESTCASE: 6
},
STEP_COMP_TS: {
B.SUBJECT_TESTPLAN: 14,
B.SUBJECT_TESTSUITE: 13
},
STEP_FIN_TC: {
B.SUBJECT_TESTCASE: 7
},
STEP_FIN_TS: {
B.SUBJECT_TESTSUITE: 14
},
STEP_FIN_TP: {
B.SUBJECT_TESTPLAN: 15
}
}
STEPS_TESTPLAN = [STEP_INIT_TP, STEP_INIT_TS, STEP_INIT_TC,
STEP_EXEC_TS1, STEP_EXEC_TC1, STEP_BREAK_AFTER_TC1, STEP_BREAK_BETWEEN_TC, STEP_BREAK_BEFORE_TC2, STEP_EXEC_TC2, STEP_EXEC_TS2,
STEP_COLL_TC, STEP_COLL_TS,
STEP_COMP_TC, STEP_COMP_TS, STEP_FIN_TP ]
STEP_COMP_TC, STEP_COMP_TS, STEP_FIN_TP]
STEPS_TESTSUITE = [ STEP_INIT_TS, STEP_INIT_TC,
STEP_EXEC_TS1, STEP_EXEC_TC1, STEP_BREAK, STEP_EXEC_TC2, STEP_EXEC_TS2,
STEP_EXEC_TS1, STEP_EXEC_TC1, STEP_BREAK_AFTER_TC1, STEP_BREAK_BETWEEN_TC, STEP_BREAK_BEFORE_TC2, STEP_EXEC_TC2, STEP_EXEC_TS2,
STEP_COLL_TC, STEP_COLL_TS,
STEP_COMP_TC, STEP_COMP_TS, STEP_FIN_TS ]
STEPS_TESTCASE = [ STEP_INIT_TC, STEP_EXEC_TC1, STEP_BREAK, STEP_EXEC_TC2,
STEPS_TESTCASE = [ STEP_INIT_TC, STEP_EXEC_TC1, STEP_BREAK_BETWEEN_TC, STEP_EXEC_TC2,
STEP_COLL_TC, STEP_COMP_TC, STEP_FIN_TC ]

14
tools/job_tool.py

@ -34,14 +34,6 @@ import clean_workspace
import init_testsuite
import test_executer
#try:
# import collect_testcase
# import compare_testcase
# import execute_testcase
# import finish_testsuite
# import init_testcase
#except Exception as e:
# pass
import tools.path_tool
import tools.file_tool
import tools.date_tool as date_tool
@ -295,7 +287,7 @@ def select_variant(job, programDef, gran, args):
elif gran in [B.PAR_TESTCASE, J.GRAN_TC]:
setParameterArgs(job, args, [B.PAR_PROJ])
print("select tc spec " + gran + " " + str(args))
testcase = model.factory.getTestcase(job, args[B.PAR_PROJ]).read_entity(job, args[B.PAR_TESTCASE])
testcase = model.factory.getTestcase(job, args[B.PAR_PROJ], name=args[B.PAR_TESTCASE])
print(str(testcase))
#if "variant" not in testcase:
# return [""]
@ -332,4 +324,6 @@ def setParameterArgs(job, args, parameter):
if hasattr(job.par, p):
continue
if p in args:
setattr(job.par, p, args[p])
setattr(job.par, p, args[p])
#

35
tools/step_tool.py

@ -14,9 +14,44 @@ b) execute specific test-entity in the test-suite-execution
"""
import basic.constants as B
import tools.data_const as D
import tools.job_const as J
# import utils.i18n_tool
LIST_ARGS = [
"start", # for starting the specified main-program
"fct" # for calling the specified component-function
]
# in specification there are used sequential numbers (testcases: 1..7, testsuites: 1..14, testplan: 1..15)
# in job-parameter there are stored unique ids
# so there are some mapping-issues:
# * start is always 1 in start_dialog - map the id for parametrization
# * getNextId depending of granularity
# * map
def getNextStepID(job, snr=0, sid="", gran=""):
if gran == "":
gran = getattr(job.par, B.PAR_GRAN)
if gran not in [B.SUBJECT_TESTPLAN, B.SUBJECT_TESTSUITE, B.SUBJECT_TESTCASE]:
raise Exception("granularty not set in parameter")
if sid == "":
snr += 1
if gran == B.SUBJECT_TESTCASE:
return J.STEPS_TESTCASE[snr - 1]
elif gran == B.SUBJECT_TESTSUITE:
return J.STEPS_TESTSUITE[snr - 1]
elif gran == B.SUBJECT_TESTPLAN:
return J.STEPS_TESTPLAN[snr - 1]
else:
return getNextStepID(job, mapStepIDtoNr(job, sid, gran))
def mapStepIDtoNr(job, sid="", gran=""):
if gran == "":
gran = getattr(job.par, B.PAR_GRAN)
if gran not in [B.SUBJECT_TESTPLAN, B.SUBJECT_TESTSUITE, B.SUBJECT_TESTCASE]:
raise Exception("granularty not set in parameter")
if sid not in J.STEPS_DEFINITON:
raise Exception("step-id does not exist {}".format(sid))
if gran not in J.STEPS_DEFINITON[sid]:
raise Exception("step-id {} does not exist in gran {}".format(sid, gran))
return J.STEPS_DEFINITON[sid][gran]
Loading…
Cancel
Save