From b7560c9ad2751d04a79ee954afd465ce9c33d50f Mon Sep 17 00:00:00 2001 From: Vincent Barbaresi Date: Thu, 28 Oct 2021 11:28:45 +0200 Subject: [PATCH] Use a different method to compute a timestamp in milliseconds for describe output() (#4476) --- moto/batch/models.py | 15 +++++++++++++-- tests/test_batch/test_batch_jobs.py | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/moto/batch/models.py b/moto/batch/models.py index 601d2b1bf..200fb7806 100644 --- a/moto/batch/models.py +++ b/moto/batch/models.py @@ -35,6 +35,15 @@ COMPUTE_ENVIRONMENT_NAME_REGEX = re.compile( ) +def datetime2int_milliseconds(date): + """ + AWS returns timestamps in milliseconds + We don't use milliseconds timestamps internally, + this method should be used only in describe() method + """ + return int(date.timestamp() * 1000) + + def datetime2int(date): return int(time.mktime(date.timetuple())) @@ -351,6 +360,7 @@ class Job(threading.Thread, BaseModel, DockerModel): self.job_queue = job_queue self.job_state = "SUBMITTED" # One of SUBMITTED | PENDING | RUNNABLE | STARTING | RUNNING | SUCCEEDED | FAILED self.job_queue.jobs.append(self) + self.job_created_at = datetime.datetime.now() self.job_started_at = datetime.datetime(1970, 1, 1) self.job_stopped_at = datetime.datetime(1970, 1, 1) self.job_stopped = False @@ -374,11 +384,12 @@ class Job(threading.Thread, BaseModel, DockerModel): "jobQueue": self.job_queue.arn, "status": self.job_state, "dependsOn": self.depends_on if self.depends_on else [], + "createdAt": datetime2int_milliseconds(self.job_created_at), } if result["status"] not in ["SUBMITTED", "PENDING", "RUNNABLE", "STARTING"]: - result["startedAt"] = datetime2int(self.job_started_at) + result["startedAt"] = datetime2int_milliseconds(self.job_started_at) if self.job_stopped: - result["stoppedAt"] = datetime2int(self.job_stopped_at) + result["stoppedAt"] = datetime2int_milliseconds(self.job_stopped_at) result["container"] = {} result["container"]["command"] = self._get_container_property("command", []) result["container"]["privileged"] = self._get_container_property( diff --git a/tests/test_batch/test_batch_jobs.py b/tests/test_batch/test_batch_jobs.py index f3d69aa10..ade9b4261 100644 --- a/tests/test_batch/test_batch_jobs.py +++ b/tests/test_batch/test_batch_jobs.py @@ -95,6 +95,7 @@ def test_submit_job_by_name(): def test_submit_job(): ec2_client, iam_client, _, logs_client, batch_client = _get_clients() _, _, _, iam_arn = _setup(ec2_client, iam_client) + start_time_milliseconds = time.time() * 1000 job_def_name = str(uuid4())[0:6] commands = ["echo", "hello"] @@ -105,6 +106,12 @@ def test_submit_job(): ) job_id = resp["jobId"] + # Test that describe_jobs() returns 'createdAt' + # github.com/spulec/moto/issues/4364 + resp = batch_client.describe_jobs(jobs=[job_id]) + created_at = resp["jobs"][0]["createdAt"] + created_at.should.be.greater_than(start_time_milliseconds) + _wait_for_job_status(batch_client, job_id, "SUCCEEDED") resp = logs_client.describe_log_streams( @@ -118,6 +125,17 @@ def test_submit_job(): ) [event["message"] for event in resp["events"]].should.equal(["hello"]) + # Test that describe_jobs() returns timestamps in milliseconds + # github.com/spulec/moto/issues/4364 + resp = batch_client.describe_jobs(jobs=[job_id]) + created_at = resp["jobs"][0]["createdAt"] + started_at = resp["jobs"][0]["startedAt"] + stopped_at = resp["jobs"][0]["stoppedAt"] + + created_at.should.be.greater_than(start_time_milliseconds) + started_at.should.be.greater_than(start_time_milliseconds) + stopped_at.should.be.greater_than(start_time_milliseconds) + @mock_logs @mock_ec2