go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/logdog/appengine/coordinator/endpoints/services/archiveStream_test.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package services
    16  
    17  import (
    18  	"errors"
    19  	"testing"
    20  	"time"
    21  
    22  	"go.chromium.org/luci/gae/filter/featureBreaker"
    23  	ds "go.chromium.org/luci/gae/service/datastore"
    24  	logdog "go.chromium.org/luci/logdog/api/endpoints/coordinator/services/v1"
    25  	"go.chromium.org/luci/logdog/appengine/coordinator"
    26  	ct "go.chromium.org/luci/logdog/appengine/coordinator/coordinatorTest"
    27  
    28  	. "github.com/smartystreets/goconvey/convey"
    29  	. "go.chromium.org/luci/common/testing/assertions"
    30  )
    31  
    32  func TestArchiveStream(t *testing.T) {
    33  	t.Parallel()
    34  
    35  	Convey(`With a testing configuration`, t, func() {
    36  		c, env := ct.Install()
    37  
    38  		svr := New(ServerSettings{NumQueues: 2})
    39  
    40  		// Register a testing log stream with an archive tasked.
    41  		env.AddProject(c, "proj-foo")
    42  		tls := ct.MakeStream(c, "proj-foo", "some-realm", "testing/+/foo")
    43  		tls.State.ArchivalKey = []byte("archival key")
    44  		So(tls.State.ArchivalState(), ShouldEqual, coordinator.ArchiveTasked)
    45  		if err := tls.Put(c); err != nil {
    46  			panic(err)
    47  		}
    48  
    49  		// Advance the clock to differentiate updates from new stream.
    50  		env.Clock.Add(time.Hour)
    51  		now := ds.RoundTime(env.Clock.Now().UTC())
    52  
    53  		req := &logdog.ArchiveStreamRequest{
    54  			Project:       string(tls.Project),
    55  			Id:            string(tls.Stream.ID),
    56  			TerminalIndex: 13,
    57  			LogEntryCount: 14,
    58  			StreamUrl:     "gs://fake.stream",
    59  			StreamSize:    10,
    60  			IndexUrl:      "gs://fake.index",
    61  			IndexSize:     20,
    62  		}
    63  
    64  		Convey(`Returns Forbidden error if not a service.`, func() {
    65  			_, err := svr.ArchiveStream(c, req)
    66  			So(err, ShouldBeRPCPermissionDenied)
    67  		})
    68  
    69  		Convey(`When logged in as a service`, func() {
    70  			env.ActAsService()
    71  
    72  			Convey(`Will mark the stream as archived.`, func() {
    73  				_, err := svr.ArchiveStream(c, req)
    74  				So(err, ShouldBeNil)
    75  
    76  				So(tls.Get(c), ShouldBeNil)
    77  				So(tls.State.Terminated(), ShouldBeTrue)
    78  				So(tls.State.ArchivalState(), ShouldEqual, coordinator.ArchivedComplete)
    79  
    80  				So(tls.State.Updated, ShouldResemble, now)
    81  				So(tls.State.ArchivalKey, ShouldBeNil)
    82  				So(tls.State.TerminatedTime, ShouldResemble, now)
    83  				So(tls.State.ArchivedTime, ShouldResemble, now)
    84  				So(tls.State.TerminalIndex, ShouldEqual, 13)
    85  				So(tls.State.ArchiveLogEntryCount, ShouldEqual, 14)
    86  				So(tls.State.ArchiveStreamURL, ShouldEqual, "gs://fake.stream")
    87  				So(tls.State.ArchiveStreamSize, ShouldEqual, 10)
    88  				So(tls.State.ArchiveIndexURL, ShouldEqual, "gs://fake.index")
    89  				So(tls.State.ArchiveIndexSize, ShouldEqual, 20)
    90  			})
    91  
    92  			Convey(`Will mark the stream as partially archived if not complete.`, func() {
    93  				req.LogEntryCount = 13
    94  
    95  				_, err := svr.ArchiveStream(c, req)
    96  				So(err, ShouldBeNil)
    97  
    98  				So(tls.Get(c), ShouldBeNil)
    99  				So(tls.State.Terminated(), ShouldBeTrue)
   100  				So(tls.State.ArchivalState(), ShouldEqual, coordinator.ArchivedPartial)
   101  
   102  				So(tls.State.Updated, ShouldResemble, now)
   103  				So(tls.State.ArchivalKey, ShouldBeNil)
   104  				So(tls.State.TerminatedTime, ShouldResemble, now)
   105  				So(tls.State.ArchivedTime, ShouldResemble, now)
   106  				So(tls.State.TerminalIndex, ShouldEqual, 13)
   107  				So(tls.State.ArchiveLogEntryCount, ShouldEqual, 13)
   108  				So(tls.State.ArchiveStreamURL, ShouldEqual, "gs://fake.stream")
   109  				So(tls.State.ArchiveStreamSize, ShouldEqual, 10)
   110  				So(tls.State.ArchiveIndexURL, ShouldEqual, "gs://fake.index")
   111  				So(tls.State.ArchiveIndexSize, ShouldEqual, 20)
   112  			})
   113  
   114  			Convey(`Will refuse to process an invalid stream hash.`, func() {
   115  				req.Id = "!!!invalid!!!"
   116  				_, err := svr.ArchiveStream(c, req)
   117  				So(err, ShouldBeRPCInvalidArgument, "Invalid ID")
   118  			})
   119  
   120  			Convey(`If index URL is missing, will refuse to mark the stream archived.`, func() {
   121  				req.IndexUrl = ""
   122  
   123  				_, err := svr.ArchiveStream(c, req)
   124  				So(err, ShouldBeRPCInvalidArgument)
   125  			})
   126  
   127  			Convey(`If stream URL is missing, will refuse to mark the stream archived.`, func() {
   128  				req.StreamUrl = ""
   129  
   130  				_, err := svr.ArchiveStream(c, req)
   131  				So(err, ShouldBeRPCInvalidArgument)
   132  			})
   133  
   134  			Convey(`If stream is already archived, will not update and return success.`, func() {
   135  				tls.State.TerminalIndex = 1337
   136  				tls.State.ArchiveLogEntryCount = 42
   137  				tls.State.ArchivedTime = now
   138  				tls.State.TerminatedTime = now
   139  
   140  				So(tls.State.Terminated(), ShouldBeTrue)
   141  				So(tls.State.ArchivalState(), ShouldEqual, coordinator.ArchivedPartial)
   142  				So(tls.Put(c), ShouldBeNil)
   143  
   144  				_, err := svr.ArchiveStream(c, req)
   145  				So(err, ShouldBeNil)
   146  
   147  				tls.State.TerminalIndex = -1 // To make sure it reloaded.
   148  				So(tls.Get(c), ShouldBeNil)
   149  				So(tls.State.Terminated(), ShouldBeTrue)
   150  				So(tls.State.ArchivalState(), ShouldEqual, coordinator.ArchivedPartial)
   151  
   152  				So(tls.State.TerminalIndex, ShouldEqual, 1337)
   153  				So(tls.State.ArchiveLogEntryCount, ShouldEqual, 42)
   154  			})
   155  
   156  			Convey(`If the archive has failed, it is archived as an empty stream.`, func() {
   157  				req.Error = "archive error"
   158  
   159  				_, err := svr.ArchiveStream(c, req)
   160  				So(err, ShouldBeNil)
   161  				So(tls.Get(c), ShouldBeNil)
   162  				So(tls.State.ArchivalState(), ShouldEqual, coordinator.ArchivedComplete)
   163  
   164  				So(tls.State.ArchivalKey, ShouldBeNil)
   165  				So(tls.State.TerminalIndex, ShouldEqual, -1)
   166  				So(tls.State.ArchiveLogEntryCount, ShouldEqual, 0)
   167  			})
   168  
   169  			Convey(`When datastore Get fails, returns internal error.`, func() {
   170  				c, fb := featureBreaker.FilterRDS(c, nil)
   171  				fb.BreakFeatures(errors.New("test error"), "GetMulti")
   172  
   173  				_, err := svr.ArchiveStream(c, req)
   174  				So(err, ShouldBeRPCInternal)
   175  			})
   176  
   177  			Convey(`When datastore Put fails, returns internal error.`, func() {
   178  				c, fb := featureBreaker.FilterRDS(c, nil)
   179  				fb.BreakFeatures(errors.New("test error"), "PutMulti")
   180  
   181  				_, err := svr.ArchiveStream(c, req)
   182  				So(err, ShouldBeRPCInternal)
   183  			})
   184  		})
   185  	})
   186  }