Commit eb68ec0f authored by GuessWhoSamFoo's avatar GuessWhoSamFoo
Browse files

Refactor job printer

Signed-off-by: default avatarGuessWhoSamFoo <foos@vmware.com>
Showing with 254 additions and 23 deletions
+254 -23
......@@ -53,44 +53,54 @@ func JobListHandler(_ context.Context, list *batchv1.JobList, opts Options) (com
}
// JobHandler printers a job.
func JobHandler(ctx context.Context, job *batchv1.Job, opts Options) (component.Component, error) {
func JobHandler(ctx context.Context, job *batchv1.Job, options Options) (component.Component, error) {
o := NewObject(job)
o.EnableEvents()
configSummary, err := createJobConfiguration(*job)
jh, err := newJobHandler(job, o)
if err != nil {
return nil, err
}
statusSummary, err := createJobStatus(*job)
if err != nil {
return nil, err
if err := jh.Config(options); err != nil {
return nil, errors.Wrap(err, "print job configuration")
}
o.RegisterConfig(configSummary)
o.RegisterSummary(statusSummary)
if err := jh.Status(options); err != nil {
return nil, errors.Wrap(err, "print job status")
}
o.EnablePodTemplate(job.Spec.Template)
if err := jh.Pods(ctx, job, options); err != nil {
return nil, errors.Wrap(err, "print job pods")
}
o.RegisterItems(ItemDescriptor{
Func: func() (component.Component, error) {
return createPodListView(ctx, job, opts)
},
Width: component.WidthFull,
})
if err := jh.Conditions(options); err != nil {
return nil, errors.Wrap(err, "print job conditions")
}
o.RegisterItems(ItemDescriptor{
Func: func() (component.Component, error) {
return createJobConditions(job.Status.Conditions)
},
Width: component.WidthFull,
})
return o.ToComponent(ctx, options)
}
o.EnableEvents()
// JobConfiguration generates a job configuration
type JobConfiguration struct {
job *batchv1.Job
}
return o.ToComponent(ctx, opts)
// NewJobConfiguration creates an instance of JobConfiguration
func NewJobConfiguration(job *batchv1.Job) *JobConfiguration {
return &JobConfiguration{
job: job,
}
}
func createJobConfiguration(job batchv1.Job) (*component.Summary, error) {
// Create creates a job configuration summary
func (j *JobConfiguration) Create(option Options) (*component.Summary, error) {
if j == nil || j.job == nil {
return nil, errors.New("job is nil")
}
job := j.job
sections := component.SummarySections{}
sections.Add("Back Off Limit", component.NewText(conversion.PtrInt32ToString(job.Spec.BackoffLimit)))
......@@ -200,3 +210,103 @@ func createJobListView(ctx context.Context, object runtime.Object, options Optio
return JobListHandler(ctx, jobList, options)
}
type jobObject interface {
Config(options Options) error
Status(options Options) error
Pods(ctx context.Context, object runtime.Object, options Options) error
Conditions(options Options) error
}
type jobHandler struct {
job *batchv1.Job
configFunc func(*batchv1.Job, Options) (*component.Summary, error)
statusFunc func(*batchv1.Job, Options) (*component.Summary, error)
podFunc func(context.Context, runtime.Object, Options) (component.Component, error)
conditionsFunc func(*batchv1.Job, Options) (*component.Table, error)
object *Object
}
var _ jobObject = (*jobHandler)(nil)
func newJobHandler(job *batchv1.Job, object *Object) (*jobHandler, error) {
if job == nil {
return nil, errors.New("can't print a nil job")
}
if object == nil {
return nil, errors.New("can't print a job using a nil object printer")
}
jh := &jobHandler{
job: job,
configFunc: defaultJobConfig,
statusFunc: defaultJobStatus,
podFunc: defaultJobPods,
conditionsFunc: defaultJobConditions,
object: object,
}
return jh, nil
}
func (j *jobHandler) Config(options Options) error {
out, err := j.configFunc(j.job, options)
if err != nil {
return err
}
j.object.RegisterConfig(out)
return nil
}
func defaultJobConfig(job *batchv1.Job, options Options) (*component.Summary, error) {
return NewJobConfiguration(job).Create(options)
}
func (j *jobHandler) Status(options Options) error {
out, err := j.statusFunc(j.job, options)
if err != nil {
return err
}
j.object.RegisterSummary(out)
return nil
}
func defaultJobStatus(job *batchv1.Job, options Options) (*component.Summary, error) {
return createJobStatus(*job)
}
func (j *jobHandler) Pods(ctx context.Context, object runtime.Object, options Options) error {
j.object.EnablePodTemplate(j.job.Spec.Template)
j.object.RegisterItems(ItemDescriptor{
Width: component.WidthFull,
Func: func() (component.Component, error) {
return j.podFunc(ctx, object, options)
},
})
return nil
}
func defaultJobPods(ctx context.Context, object runtime.Object, options Options) (component.Component, error) {
return createPodListView(ctx, object, options)
}
func (j *jobHandler) Conditions(options Options) error {
if j.job == nil {
return errors.New("can;t display conditions for nil job")
}
j.object.RegisterItems(ItemDescriptor{
Width: component.WidthFull,
Func: func() (component.Component, error) {
return j.conditionsFunc(j.job, options)
},
})
return nil
}
func defaultJobConditions(job *batchv1.Job, options Options) (*component.Table, error) {
return createJobConditions(job.Status.Conditions)
}
......@@ -8,10 +8,14 @@ package printer
import (
"context"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware/octant/internal/conversion"
"github.com/vmware/octant/internal/testutil"
......@@ -69,3 +73,120 @@ func Test_JobListHandler(t *testing.T) {
component.AssertEqual(t, expected, got)
}
func Test_JobConfiguration(t *testing.T) {
var backofflimit int32 = 4
var completions int32 = 1
var parallelism int32 = 1
job := testutil.CreateJob("job")
job.Spec.BackoffLimit = &backofflimit
job.Spec.Completions = &completions
job.Spec.Parallelism = &parallelism
cases := []struct {
name string
job *batchv1.Job
isErr bool
expected *component.Summary
}{
{
name: "general",
job: job,
expected: component.NewSummary("Configuration", []component.SummarySection{
{
Header: "Back Off Limit",
Content: component.NewText("4"),
},
{
Header: "Completions",
Content: component.NewText("1"),
},
{
Header: "Parallelism",
Content: component.NewText("1"),
},
}...),
},
{
name: "job is nil",
job: nil,
isErr: true,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
tpo := newTestPrinterOptions(controller)
printOptions := tpo.ToOptions()
jh := NewJobConfiguration(tc.job)
summary, err := jh.Create(printOptions)
if tc.isErr {
require.Error(t, err)
return
}
require.NoError(t, err)
component.AssertEqual(t, tc.expected, summary)
})
}
}
func Test_createJobStatus(t *testing.T) {
job := testutil.CreateJob("job")
job.Status.Succeeded = int32(1)
job.Status.StartTime = &metav1.Time{Time: testutil.Time()}
job.Status.CompletionTime = &metav1.Time{Time: time.Now()}
got, err := createJobStatus(*job)
require.NoError(t, err)
sections := component.SummarySections{
{Header: "Started", Content: component.NewTimestamp(testutil.Time())},
{Header: "Completed", Content: component.NewTimestamp(time.Now())},
{Header: "Succeeded", Content: component.NewText("1")},
}
expected := component.NewSummary("Status", sections...)
assert.Equal(t, expected, got)
}
func Test_createJobConditions(t *testing.T) {
now := metav1.Time{Time: time.Now()}
job := testutil.CreateJob("job")
job.Status.Conditions = []batchv1.JobCondition{
{
Type: batchv1.JobComplete,
LastProbeTime: now,
LastTransitionTime: now,
Status: corev1.ConditionTrue,
Message: "message",
Reason: "reason",
},
}
got, err := createJobConditions(job.Status.Conditions)
require.NoError(t, err)
cols := component.NewTableCols("Type", "Last Probe", "Last Transition",
"Status", "Message", "Reason")
expected := component.NewTable("Conditions", "There are no job conditions!", cols)
expected.Add([]component.TableRow{
{
"Type": component.NewText("Complete"),
"Last Probe": component.NewTimestamp(now.Time),
"Last Transition": component.NewTimestamp(now.Time),
"Status": component.NewText("True"),
"Message": component.NewText("message"),
"Reason": component.NewText("reason"),
},
}...)
component.AssertEqual(t, expected, got)
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment