Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Commit

Permalink
Implement with_tasks option to expand the task information (#3343)
Browse files Browse the repository at this point in the history
* Implement with_tasks option to expand the task information

* Added tests

* format
  • Loading branch information
chkeita committed Jul 26, 2023
1 parent fc4e698 commit 8cb761a
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 22 deletions.
12 changes: 8 additions & 4 deletions src/ApiService/ApiService/Functions/Jobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,14 @@ public class Jobs {

static JobTaskInfo TaskToJobTaskInfo(Task t) => new(t.TaskId, t.Config.Task.Type, t.State);

// TODO: search.WithTasks is not checked in Python code?

var taskInfo = await _context.TaskOperations.SearchStates(jobId).Select(TaskToJobTaskInfo).ToListAsync();
return await RequestHandling.Ok(req, JobResponse.ForJob(job, taskInfo));
var tasks = _context.TaskOperations.SearchStates(jobId);
if (search.WithTasks ?? false) {
var ts = await tasks.ToListAsync();
return await RequestHandling.Ok(req, JobResponse.ForJob(job, ts));
} else {
var taskInfo = await tasks.Select(TaskToJobTaskInfo).ToListAsync();
return await RequestHandling.Ok(req, JobResponse.ForJob(job, taskInfo));
}
}

var jobs = await _context.JobOperations.SearchState(states: search.State ?? Enumerable.Empty<JobState>()).ToListAsync();
Expand Down
13 changes: 11 additions & 2 deletions src/ApiService/ApiService/OneFuzzTypes/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ public record Task(
ISecret<Authentication>? Auth = null,
DateTimeOffset? Heartbeat = null,
DateTimeOffset? EndTime = null,
StoredUserInfo? UserInfo = null) : StatefulEntityBase<TaskState>(State) {
StoredUserInfo? UserInfo = null) : StatefulEntityBase<TaskState>(State), IJobTaskInfo {
public TaskType Type => Config.Task.Type;
}

public record TaskEvent(
Expand Down Expand Up @@ -898,11 +899,19 @@ public record JobConfig(
}
}

[JsonDerivedType(typeof(Task), typeDiscriminator: "Task")]
[JsonDerivedType(typeof(JobTaskInfo), typeDiscriminator: "JobTaskInfo")]
public interface IJobTaskInfo {
Guid TaskId { get; }
TaskType Type { get; }
TaskState State { get; }
}

public record JobTaskInfo(
Guid TaskId,
TaskType Type,
TaskState State
);
) : IJobTaskInfo;

public record Job(
[PartitionKey][RowKey] Guid JobId,
Expand Down
4 changes: 2 additions & 2 deletions src/ApiService/ApiService/OneFuzzTypes/Responses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ public record JobResponse(
JobConfig Config,
string? Error,
DateTimeOffset? EndTime,
List<JobTaskInfo>? TaskInfo,
IEnumerable<IJobTaskInfo>? TaskInfo,
StoredUserInfo? UserInfo,
[property: JsonPropertyName("Timestamp")] // must retain capital T for backcompat
DateTimeOffset? Timestamp
// not including UserInfo from Job model
) : BaseResponse() {
public static JobResponse ForJob(Job j, List<JobTaskInfo>? taskInfo)
public static JobResponse ForJob(Job j, IEnumerable<IJobTaskInfo>? taskInfo)
=> new(
JobId: j.JobId,
State: j.State,
Expand Down
51 changes: 51 additions & 0 deletions src/ApiService/IntegrationTests/JobsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,55 @@ public JobsTestBase(ITestOutputHelper output, IStorage storage)
var metadata = Assert.Single(container.Value);
Assert.Equal(new KeyValuePair<string, string>("container_type", "logs"), metadata);
}


[Fact]
public async Async.Task Get_CanFindSpecificJobWithTaskInfo() {

var taskConfig = new TaskConfig(_jobId, new List<Guid>(), new TaskDetails(TaskType.Coverage, 60));
var task = new Task(_jobId, Guid.NewGuid(), TaskState.Running, Os.Windows, taskConfig);

await Context.InsertAll(
new Job(_jobId, JobState.Stopped, _config, null), task);

var func = new Jobs(Context, LoggerProvider.CreateLogger<Jobs>());

var ctx = new TestFunctionContext();
var result = await func.Run(TestHttpRequestData.FromJson("GET", new JobSearch(JobId: _jobId, WithTasks: false)), ctx);
Assert.Equal(HttpStatusCode.OK, result.StatusCode);

var response = BodyAs<JobResponse>(result);
Assert.Equal(_jobId, response.JobId);
Assert.NotNull(response.TaskInfo);
var returnedTasks = response.TaskInfo.OfType<JobTaskInfo>().ToList();
Assert.NotEmpty(returnedTasks);
Assert.Equal(task.TaskId, returnedTasks[0].TaskId);
Assert.Equal(task.State, returnedTasks[0].State);
Assert.Equal(task.Config.Task.Type, returnedTasks[0].Type);
}

[Fact]
public async Async.Task Get_CanFindSpecificJobWithFullTask() {
var taskConfig = new TaskConfig(_jobId, new List<Guid>(), new TaskDetails(TaskType.Coverage, 60));
var task = new Task(_jobId, Guid.NewGuid(), TaskState.Running, Os.Windows, taskConfig);

await Context.InsertAll(
new Job(_jobId, JobState.Stopped, _config, null), task);

var func = new Jobs(Context, LoggerProvider.CreateLogger<Jobs>());

var ctx = new TestFunctionContext();
var result = await func.Run(TestHttpRequestData.FromJson("GET", new JobSearch(JobId: _jobId, WithTasks: true)), ctx);
Assert.Equal(HttpStatusCode.OK, result.StatusCode);

var response = BodyAs<JobResponse>(result);
Assert.Equal(_jobId, response.JobId);
Assert.NotNull(response.TaskInfo);
var returnedTasks = response.TaskInfo.OfType<Task>().ToList();
Assert.NotEmpty(returnedTasks);
Assert.Equal(task.TaskId, returnedTasks[0].TaskId);
Assert.Equal(task.State, returnedTasks[0].State);
Assert.Equal(task.Config.Task.Type, returnedTasks[0].Type);

}
}
6 changes: 4 additions & 2 deletions src/cli/onefuzz/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1308,14 +1308,16 @@ def delete(self, job_id: UUID_EXPANSION) -> models.Job:
"DELETE", models.Job, data=requests.JobGet(job_id=job_id_expanded)
)

def get(self, job_id: UUID_EXPANSION) -> models.Job:
def get(self, job_id: UUID_EXPANSION, with_tasks: bool = False) -> models.Job:
"""Get information about a specific job"""
job_id_expanded = self._disambiguate_uuid(
"job_id", job_id, lambda: [str(x.job_id) for x in self.list()]
)
self.logger.debug("get job: %s", job_id_expanded)
job = self._req_model(
"GET", models.Job, data=requests.JobGet(job_id=job_id_expanded)
"GET",
models.Job,
data=requests.JobGet(job_id=job_id_expanded, with_tasks=with_tasks),
)
return job

Expand Down
22 changes: 11 additions & 11 deletions src/pytypes/onefuzztypes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,17 +463,6 @@ class JobTaskInfo(BaseModel):
state: TaskState


class Job(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
job_id: UUID = Field(default_factory=uuid4)
state: JobState = Field(default=JobState.init)
config: JobConfig
error: Optional[str]
end_time: Optional[datetime] = None
task_info: Optional[List[JobTaskInfo]]
user_info: Optional[UserInfo]


class TaskHeartbeatEntry(BaseModel):
task_id: UUID
job_id: Optional[UUID]
Expand Down Expand Up @@ -757,6 +746,17 @@ class Task(BaseModel):
user_info: Optional[UserInfo]


class Job(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
job_id: UUID = Field(default_factory=uuid4)
state: JobState = Field(default=JobState.init)
config: JobConfig
error: Optional[str]
end_time: Optional[datetime] = None
task_info: Optional[List[Union[Task, JobTaskInfo]]]
user_info: Optional[UserInfo]


class NetworkConfig(BaseModel):
address_space: str = Field(default="10.0.0.0/8")
subnet: str = Field(default="10.0.0.0/16")
Expand Down
2 changes: 1 addition & 1 deletion src/pytypes/onefuzztypes/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ class BaseRequest(BaseModel):

class JobGet(BaseRequest):
job_id: UUID
with_tasks: Optional[bool]


class JobSearch(BaseRequest):
job_id: Optional[UUID]
state: Optional[List[JobState]]
task_state: Optional[List[TaskState]]
with_tasks: Optional[bool]


class NotificationCreate(BaseRequest, NotificationConfig):
Expand Down

0 comments on commit 8cb761a

Please sign in to comment.