github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/automation/spec/run.go (about)

     1  package spec
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/google/go-cmp/cmp"
    10  	"github.com/qri-io/qri/automation/run"
    11  	"github.com/qri-io/qri/automation/workflow"
    12  	"github.com/qri-io/qri/base/params"
    13  )
    14  
    15  // AssertRunStore confirms the expected behavior of a run.Store interface
    16  func AssertRunStore(t *testing.T, store run.Store) {
    17  	ctx := context.Background()
    18  	assertCreatePut(ctx, t, store)
    19  
    20  	wid := workflow.ID("test id")
    21  	expectedRuns := [3]*run.State{}
    22  	now := time.Now()
    23  	for i := 2; i >= 0; i-- {
    24  		r := &run.State{WorkflowID: wid}
    25  		st := now.Add(time.Duration(0-i) * time.Hour)
    26  		et := st.Add(time.Minute)
    27  		r.StartTime = &st
    28  		r.StopTime = &et
    29  		if i == 0 {
    30  			r.Status = run.RSWaiting
    31  		}
    32  		expectedRun, err := store.Create(ctx, r)
    33  		if err != nil {
    34  			t.Fatalf("store.Put unexpected error: %s", err)
    35  		}
    36  		expectedRuns[i] = expectedRun
    37  	}
    38  
    39  	if _, err := store.Get(ctx, "bad run id"); !errors.Is(err, run.ErrNotFound) {
    40  		t.Fatalf("store.Get should emit a run.ErrNotFound error if given an unknown run ID")
    41  	}
    42  	for i := 0; i < 3; i++ {
    43  		got, err := store.Get(ctx, expectedRuns[i].ID)
    44  		if err != nil {
    45  			t.Fatalf("store.Get unexpected error: %s", err)
    46  		}
    47  
    48  		if diff := cmp.Diff(expectedRuns[i], got); diff != "" {
    49  			t.Errorf("store.Get i=%d mismatch (-want +got):\n%s", i, diff)
    50  		}
    51  	}
    52  
    53  	badWID := workflow.ID("bad id")
    54  	if _, err := store.Count(ctx, badWID); !errors.Is(err, run.ErrUnknownWorkflowID) {
    55  		t.Fatalf("store.Count should emit a run.ErrUnknownWorkflowID error when given a workflow ID not associated with any runs in the Store")
    56  	}
    57  
    58  	gotCount, err := store.Count(ctx, wid)
    59  	if err != nil {
    60  		t.Fatalf("store.Count unexpected error: %s", err)
    61  	}
    62  	if gotCount != 3 {
    63  		t.Errorf("store.Count count mismatch, expected 3, got %d", gotCount)
    64  	}
    65  
    66  	if _, err := store.List(ctx, badWID, params.ListAll); !errors.Is(err, run.ErrUnknownWorkflowID) {
    67  		t.Fatalf("store.List should emit a run.ErrUnknownWorkflowID error when given a workflow ID not associated with any runs in the Store")
    68  	}
    69  	gotRuns, err := store.List(ctx, wid, params.ListAll)
    70  	if err != nil {
    71  		t.Fatalf("store.List unexpected error: %s", err)
    72  	}
    73  	if diff := cmp.Diff(expectedRuns[:], gotRuns); diff != "" {
    74  		t.Errorf("store.List mismatch (-want +got):\n%s", diff)
    75  	}
    76  
    77  	if _, err := store.GetLatest(ctx, badWID); !errors.Is(err, run.ErrUnknownWorkflowID) {
    78  		t.Fatalf("store.GetLatest should emit a run.ErrUnknownWorkflowID error when given a workflow ID not associated with any runs in the Store")
    79  	}
    80  	got, err := store.GetLatest(ctx, wid)
    81  	if err != nil {
    82  		t.Fatalf("store.GetLatest unexpected error: %s", err)
    83  	}
    84  	if diff := cmp.Diff(expectedRuns[0], got); diff != "" {
    85  		t.Errorf("store.GetLatest mismatch (-want +got): \n%s", diff)
    86  	}
    87  
    88  	if _, err := store.GetStatus(ctx, badWID); !errors.Is(err, run.ErrUnknownWorkflowID) {
    89  		t.Fatalf("store.GetStatus should emit a run.ErrUnknownWorkflowID error when given a workflow ID not associated with any runs in the Store")
    90  	}
    91  	gotStatus, err := store.GetStatus(ctx, wid)
    92  	if err != nil {
    93  		t.Fatalf("store.GetStatus unexpected error: %s", err)
    94  	}
    95  	if gotStatus != run.RSWaiting {
    96  		t.Errorf("store.GetStatus mismatch: expected %q, got %q", run.RSWaiting, gotStatus)
    97  	}
    98  
    99  	gotRuns, err = store.ListByStatus(ctx, "", run.RSWaiting, params.ListAll)
   100  	if err != nil {
   101  		t.Fatalf("store.ListByStatus unexpected error: %s", err)
   102  	}
   103  
   104  	if diff := cmp.Diff(expectedRuns[:1], gotRuns); diff != "" {
   105  		t.Errorf("store.ListByStatus mismatch (-want +got): \n%s", diff)
   106  	}
   107  }
   108  
   109  // assertCreatePut confirms the expected behavior of the run.Store's Put method
   110  func assertCreatePut(ctx context.Context, t *testing.T, store run.Store) {
   111  	if _, err := store.Create(ctx, nil); err == nil {
   112  		t.Fatal("store.Create should error when passed nil")
   113  	}
   114  	expected := &run.State{}
   115  	if _, err := store.Create(ctx, expected); !errors.Is(err, run.ErrNoWorkflowID) {
   116  		t.Fatal("store.Create is expected to emit a run.ErrNoWorkflowID error if you try to create a run.State wit no workflow.ID")
   117  	}
   118  
   119  	wid := workflow.ID("assert test id")
   120  	expected.WorkflowID = wid
   121  
   122  	got, err := store.Create(ctx, expected)
   123  	if err != nil {
   124  		t.Fatalf("store.Create unexpected error: %s", err)
   125  	}
   126  	if got.ID == "" {
   127  		t.Fatal("store.Create is expected to fill the run.ID field if given a run.State with an empty ID")
   128  	}
   129  	if _, err := store.Create(ctx, got); err == nil {
   130  		t.Fatal("store.Create is expected to error if trying to create a run State with a run ID that already exists in the store")
   131  	}
   132  
   133  	got, err = store.Create(ctx, expected)
   134  	if err != nil {
   135  		t.Fatalf("store.Create should be able to add multiple entries for a single workflow.ID. Unexpected error %s", err)
   136  	}
   137  
   138  	if _, err := store.Put(ctx, nil); err == nil {
   139  		t.Fatal("store.Put should error when passed nil")
   140  	}
   141  
   142  	if _, err := store.Put(ctx, &run.State{}); err == nil {
   143  		t.Fatal("store.Put should error when passed a State with no run ID")
   144  	}
   145  	if _, err := store.Put(ctx, &run.State{ID: "test_id"}); err == nil {
   146  		t.Fatal("store.Put should error if you try to add a run.State with no workflow.ID")
   147  	}
   148  	if _, err := store.Put(ctx, &run.State{ID: "test_id", WorkflowID: "test workflow ID"}); err == nil {
   149  		t.Fatal("store.Put should error when passed a new State")
   150  	}
   151  	runID := got.ID
   152  	expected.ID = runID
   153  	expected.Status = run.RSRunning
   154  	got, err = store.Put(ctx, expected)
   155  	if err != nil {
   156  		t.Fatalf("store.Put unexpected error: %s", err)
   157  	}
   158  	if diff := cmp.Diff(expected, got); diff != "" {
   159  		t.Errorf("run.State mismatch (-want +got):\n%s", diff)
   160  	}
   161  
   162  	if _, err := store.Put(ctx, expected); err != nil {
   163  		t.Fatalf("store.Put should be able to update the same run multiple times. Unexpected error: %s", err)
   164  	}
   165  
   166  	expected.ID = runID
   167  	expected.WorkflowID = workflow.ID("new id")
   168  	if _, err = store.Put(ctx, expected); err == nil {
   169  		t.Fatal("store.Put should error if the WorkflowID of the given run.State does not match the WorkflowID of the run.State stored")
   170  	}
   171  	count, err := store.Count(ctx, got.WorkflowID)
   172  	if err != nil {
   173  		t.Fatalf("store.Count unexpected error %s", err)
   174  	}
   175  	if count != 2 {
   176  		t.Fatalf("store.Create/store.Put error: creating a new run should increment the run count, updating a run using run.Put should NOT increment the run count. Expected count of %d, got %d", 2, count)
   177  	}
   178  }