def test_job_description_attributes():
    # attributes serialization
    attrs = {'j1_name': 'j1', 'j1_var1': 'var1'}
    j = Job(name='j1',
            execution=JobExecution(exec='/bin/date'),
            resources=JobResources(numCores=1),
            attributes=attrs)
    assert all((len(j.attributes) == len(attrs), j.attributes == attrs))
    j_json = j.to_json()
    j_clone = Job(**json.loads(j_json))
    assert all(
        (len(j_clone.attributes) == len(attrs), j_clone.attributes == attrs))
    assert j.to_dict() == j_clone.to_dict()

    # attributes wrong format
    with pytest.raises(IllegalJobDescription):
        Job(name='j1',
            execution=JobExecution(exec='/bin/date'),
            resources=JobResources(numCores=1),
            attributes="some_illegal_attributes")
    with pytest.raises(IllegalJobDescription):
        Job(name='j1',
            execution=JobExecution(exec='/bin/date'),
            resources=JobResources(numCores=1),
            attributes=["some_illegal_attributes", "more_illegal_attributes"])
def test_job_description_serialization():
    # gpu cr
    jobd = """{ "name": "job1", 
              "execution": { "exec": "/bin/date", "stdin": "in_file", "stdout": "out_file", "stderr": "err_file",
                "modules": [ "python/3.6" ], "venv": [ "venv-3.6" ] },
              "resources": { "numCores": { "min": 2, "max": 4}, "numNodes": { "min": 1, "max": 2}, "nodeCrs": { "gpu": 1 } } }"""
    job = Job(**json.loads(jobd))
    assert job, "Job with node consumable resources (gpu)"
    job_dict = job.to_dict()

    job_clone = json.loads(job.to_json())
    assert job_dict == job_clone
def test_job_description_iterations():
    # no iterations
    jobd = """{ "name": "job1", 
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert not job.has_iterations

    # valid iterations
    jobd = """{ "name": "job1", 
              "iteration": { "start": 0, "stop": 10 },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert all((job.has_iterations, job.iteration.iterations() == 10))
    assert all(job.iteration.in_range(i) for i in range(10))
    assert all(not job.iteration.in_range(i) for i in range(10, 20))

    # valid iterations with default start
    jobd = """{ "name": "job1", 
              "iteration": { "stop": 10 },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert all((job.has_iterations, job.iteration.iterations() == 10))
    assert all(job.iteration.in_range(i) for i in range(10))
    assert all(not job.iteration.in_range(i) for i in range(10, 20))

    # valid iterations
    jobd = """{ "name": "job1", 
              "iteration": { "start": 5, "stop": 10 },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert all((job.has_iterations, job.iteration.iterations() == 5))
    assert all(job.iteration.in_range(i) for i in range(5, 10))
    assert all(not job.iteration.in_range(i) for i in range(0, 5))

    # not valid iteration type
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
                  "iteration": [ 5, 10 ],
                  "execution": { "exec": "/bin/date" },
                  "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # not valid iteration spec
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
                  "iteration": {  },
                  "execution": { "exec": "/bin/date" },
                  "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # not valid iteration spec
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
                  "iteration": { "iterations": 5 },
                  "execution": { "exec": "/bin/date" },
                  "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # not valid iteration spec
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
                  "iteration": { "start": 5, "stop": 0, "step": 2 },
                  "execution": { "exec": "/bin/date" },
                  "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # wrong iteration range
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
                  "iteration": { "start": 5, "stop": 0 },
                  "execution": { "exec": "/bin/date" },
                  "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # wrong iteration range
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
                  "iteration": { "start": 5, "stop": 5 },
                  "execution": { "exec": "/bin/date" },
                  "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # json serialization
    jit = JobIteration(start=0, stop=10)
    jit_json = jit.to_json()

    jit_clone = JobIteration(**json.loads(jit_json))
    jit.to_dict() == jit_clone.to_dict()

    # string serialization
    assert str(jit) == '{}-{}'.format(0, 10)

    # serialization
    jobd = """{ "name": "job1", 
              "iteration": { "start": 5, "stop": 10 },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert job, "Job with dependencies"
    job_dict = job.to_dict()

    job_clone = json.loads(job.to_json())
    assert job_dict == job_clone
def test_job_description_dependencies():
    # simple dependencies
    jobd = """{ "name": "job1", 
              "dependencies": { "after": [ "job2" ] },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert all((len(job.dependencies.after) == 1, 'job2'
                in job.dependencies.after))

    # valid dependencies
    jobd = """{ "name": "job1", 
              "dependencies": { "after": [ "job2", "job3" ] },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert all((len(job.dependencies.after) == 2, 'job2'
                in job.dependencies.after, 'job3' in job.dependencies.after))

    jobd = """{ "name": "job1", 
              "dependencies": { "after": [ "job2", "job3" ] },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert job.has_dependencies

    jobd = """{ "name": "job1", 
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert not job.has_dependencies

    jobd = """{ "name": "job1", 
              "dependencies": { "after": [  ] },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert not job.has_dependencies

    # dependencies not as list
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
                  "dependencies": { "after": "job2" },
                  "execution": { "exec": "/bin/date" },
                  "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # wrong keyword in job dependencies
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
              "dependencies": { "whenever": "job2" },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # wrong type of job dependencies
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
              "dependencies": { "after": { "job": "job2" } },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # wrong elements of job dependencies
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
              "dependencies": { "after": [ "job2", [ "job3", "job4" ] ] },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # wrong type of job dependencies
    with pytest.raises(IllegalJobDescription):
        jobd = """{ "name": "job1", 
              "dependencies": [ { "after": [ "job2", [ "job3", "job4" ] ] } ],
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
        Job(**json.loads(jobd))

    # json serialization
    jdep = JobDependencies(after=["job2", "job3"])
    jdep_json = jdep.to_json()
    assert all((jdep.has_dependencies, len(jdep.after) == 2, 'job2'
                in jdep.after, 'job3' in jdep.after))

    print("job dependencies as json: {}".format(jdep_json))
    jdep_clone = JobDependencies(**json.loads(jdep_json))
    jdep.to_dict() == jdep_clone.to_dict()

    # serialization
    jobd = """{ "name": "job1", 
              "dependencies": { "after": [ "job2", "job3" ] },
              "execution": { "exec": "/bin/date" },
              "resources": { "numCores": 2 } }"""
    job = Job(**json.loads(jobd))
    assert job, "Job with dependencies"
    job_dict = job.to_dict()

    job_clone = json.loads(job.to_json())
    assert job_dict == job_clone