github.com/GoogleCloudPlatform/testgrid@v0.0.174/util/queue/persist_test.go (about)

     1  /*
     2  Copyright 2022 The TestGrid Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package queue
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"testing"
    24  	"time"
    25  
    26  	"cloud.google.com/go/storage"
    27  	"github.com/GoogleCloudPlatform/testgrid/util/gcs"
    28  	"github.com/GoogleCloudPlatform/testgrid/util/gcs/fake"
    29  	"github.com/google/go-cmp/cmp"
    30  	"github.com/sirupsen/logrus"
    31  )
    32  
    33  func TestFixPersistent(t *testing.T) {
    34  	now := time.Now().Round(time.Second)
    35  	next := now.Add(time.Minute)
    36  	later := now.Add(time.Hour)
    37  	cases := []struct {
    38  		name        string
    39  		q           *Queue
    40  		currently   fake.Object
    41  		ticks       []time.Time
    42  		fixes       map[string]time.Time
    43  		wantCurrent map[string]time.Time
    44  		wantBuf     string
    45  	}{
    46  		{
    47  			name:        "basic",
    48  			q:           &Queue{},
    49  			wantCurrent: map[string]time.Time{},
    50  		},
    51  		{
    52  			name: "no load",
    53  			q: func() *Queue {
    54  				var q Queue
    55  				q.Init(logrus.New(), []string{"foo", "bar"}, next)
    56  				return &q
    57  			}(),
    58  			wantCurrent: map[string]time.Time{
    59  				"foo": next,
    60  				"bar": next,
    61  			},
    62  		},
    63  		{
    64  			name: "load empty",
    65  			q: func() *Queue {
    66  				var q Queue
    67  				q.Init(logrus.New(), []string{"foo", "bar"}, next)
    68  				return &q
    69  			}(),
    70  			ticks: []time.Time{now},
    71  			wantCurrent: map[string]time.Time{
    72  				"foo": next,
    73  				"bar": next,
    74  			},
    75  		},
    76  		{
    77  			name: "load",
    78  			q: func() *Queue {
    79  				var q Queue
    80  				q.Init(logrus.New(), []string{"keep-next", "bump-to-now"}, next)
    81  				return &q
    82  			}(),
    83  			ticks: []time.Time{now},
    84  			currently: fake.Object{
    85  				Data: func() string {
    86  					saved := map[string]time.Time{
    87  						"keep-next":   later,
    88  						"bump-to-now": now,
    89  						"ignore-old":  now,
    90  					}
    91  					buf, err := json.Marshal(saved)
    92  					if err != nil {
    93  						t.Fatalf("Failed to marshal: %v", err)
    94  					}
    95  					return string(buf)
    96  				}(),
    97  				Attrs: &storage.ReaderObjectAttrs{},
    98  			},
    99  			wantCurrent: map[string]time.Time{
   100  				"keep-next":   next,
   101  				"bump-to-now": now,
   102  			},
   103  		},
   104  		{
   105  			name: "load err",
   106  			q: func() *Queue {
   107  				var q Queue
   108  				q.Init(logrus.New(), []string{"keep-next", "would-bump-to-now-if-read"}, next)
   109  				return &q
   110  			}(),
   111  			ticks: []time.Time{now},
   112  			currently: fake.Object{
   113  				Data: func() string {
   114  					saved := map[string]time.Time{
   115  						"keep-next":                 later,
   116  						"would-bump-to-now-if-read": now,
   117  					}
   118  					buf, err := json.Marshal(saved)
   119  					if err != nil {
   120  						t.Fatalf("Failed to marshal: %v", err)
   121  					}
   122  					return string(buf)
   123  				}(),
   124  				Attrs:   &storage.ReaderObjectAttrs{},
   125  				OpenErr: errors.New("fake open error"),
   126  			},
   127  			wantCurrent: map[string]time.Time{
   128  				"keep-next":                 next,
   129  				"would-bump-to-now-if-read": next,
   130  			},
   131  		},
   132  		{
   133  			name: "load and save",
   134  			q: func() *Queue {
   135  				var q Queue
   136  				q.Init(logrus.New(), []string{"keep-next", "bump-to-now"}, next)
   137  				return &q
   138  			}(),
   139  			ticks: []time.Time{now, now, now},
   140  			currently: fake.Object{
   141  				Data: func() string {
   142  					saved := map[string]time.Time{
   143  						"keep-next":   later,
   144  						"bump-to-now": now,
   145  						"ignore-old":  now,
   146  					}
   147  					buf, err := json.Marshal(saved)
   148  					if err != nil {
   149  						t.Fatalf("Failed to marshal: %v", err)
   150  					}
   151  					return string(buf)
   152  				}(),
   153  				Attrs: &storage.ReaderObjectAttrs{},
   154  			},
   155  			wantCurrent: map[string]time.Time{
   156  				"keep-next":   next,
   157  				"bump-to-now": now,
   158  			},
   159  			wantBuf: func() string {
   160  				saved := map[string]time.Time{
   161  					"keep-next":   next,
   162  					"bump-to-now": now,
   163  				}
   164  				buf, err := json.MarshalIndent(saved, "", "  ")
   165  				if err != nil {
   166  					t.Fatalf("Failed to marshal: %v", err)
   167  				}
   168  				return string(buf)
   169  			}(),
   170  		},
   171  	}
   172  
   173  	path, err := gcs.NewPath("gs://fake-bucket/path/to/whatever")
   174  	if err != nil {
   175  		t.Fatalf("NewPath(): %v", err)
   176  	}
   177  
   178  	for _, tc := range cases {
   179  		t.Run(tc.name, func(t *testing.T) {
   180  			client := fake.UploadClient{
   181  				Uploader: fake.Uploader{},
   182  				Client: fake.Client{
   183  					Opener: fake.Opener{
   184  						Paths: map[gcs.Path]fake.Object{
   185  							*path: tc.currently,
   186  						},
   187  					},
   188  				},
   189  			}
   190  			ch := make(chan time.Time)
   191  			fix := FixPersistent(logrus.WithField("name", tc.name), client, *path, ch)
   192  			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   193  			defer cancel()
   194  			go func() {
   195  				for _, tick := range tc.ticks {
   196  					ch <- tick
   197  				}
   198  				cancel()
   199  			}()
   200  			if err := fix(ctx, tc.q); !errors.Is(err, context.Canceled) {
   201  				t.Errorf("fix() returned unexpected error: %v", err)
   202  			} else {
   203  				got := tc.q.Current()
   204  				if diff := cmp.Diff(tc.wantCurrent, got); diff != "" {
   205  					t.Errorf("fix() got unexpected current diff (-want +got):\n%s", diff)
   206  				}
   207  				gotBytes := string(client.Uploader[*path].Buf)
   208  				if diff := cmp.Diff(tc.wantBuf, gotBytes); diff != "" {
   209  					t.Errorf("fix() got unexpected byte diff (-want +got):\n%s", diff)
   210  				}
   211  
   212  			}
   213  		})
   214  	}
   215  }