go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/logdog/client/butler/callback_text_wrapper_test.go (about) 1 // Copyright 2018 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 butler 16 17 import ( 18 "fmt" 19 "testing" 20 21 "go.chromium.org/luci/logdog/api/logpb" 22 23 . "github.com/smartystreets/goconvey/convey" 24 . "go.chromium.org/luci/common/testing/assertions" 25 ) 26 27 type line struct { 28 value string 29 delim string 30 } 31 32 func mkTextLogEntry(lines []line, seq uint64) *logpb.LogEntry { 33 logLines := make([]*logpb.Text_Line, 0, len(lines)) 34 for _, l := range lines { 35 logLines = append(logLines, &logpb.Text_Line{ 36 Value: []byte(l.value), 37 Delimiter: l.delim, 38 }) 39 } 40 le := &logpb.LogEntry{ 41 Sequence: seq, 42 Content: &logpb.LogEntry_Text{ 43 Text: &logpb.Text{Lines: logLines}, 44 }, 45 } 46 return le 47 } 48 49 func mkWrappedTextCb(values *[]string, seq *[]uint64) StreamChunkCallback { 50 cb := func(le *logpb.LogEntry) { 51 if le == nil { 52 return 53 } 54 for _, l := range le.GetText().Lines { 55 *values = append(*values, fmt.Sprintf( 56 "%s!%s", string(l.Value), l.Delimiter, 57 )) 58 } 59 *seq = append(*seq, le.Sequence) 60 } 61 return getWrappedTextCallback(cb) 62 } 63 64 func TestTextReassembler(t *testing.T) { 65 t.Parallel() 66 67 Convey(`Callback wrapper works`, t, func() { 68 Convey(`With nil`, func() { 69 values, seq := []string{}, []uint64{} 70 mkWrappedTextCb(&values, &seq)(nil) 71 So(values, ShouldResemble, []string{}) 72 }) 73 74 Convey(`With only complete lines`, func() { 75 values, seq := []string{}, []uint64{} 76 mkWrappedTextCb(&values, &seq)(mkTextLogEntry([]line{ 77 {"hi", "\n"}, 78 {"there", "\n"}, 79 }, 0)) 80 So(values, ShouldResemble, []string{ 81 "hi!\n", 82 "there!\n", 83 }) 84 So(seq, ShouldResemble, []uint64{0}) 85 }) 86 87 Convey(`With partial lines`, func() { 88 values, seq := []string{}, []uint64{} 89 cbWrapped := mkWrappedTextCb(&values, &seq) 90 91 Convey(`At the beginning of a LogEntry`, func() { 92 cbWrapped(mkTextLogEntry([]line{ 93 {"h", ""}, 94 }, 0)) 95 So(values, ShouldResemble, []string{}) 96 So(seq, ShouldResemble, []uint64{}) 97 }) 98 99 Convey(`At the end of a LogEntry`, func() { 100 cbWrapped(mkTextLogEntry([]line{ 101 {"hi", "\n"}, 102 {"there", "\n"}, 103 {"ho", ""}, 104 }, 0)) 105 So(values, ShouldResemble, []string{ 106 "hi!\n", 107 "there!\n", 108 }) 109 So(seq, ShouldResemble, []uint64{0}) 110 111 Convey(`And correctly completes with the next LogEntry`, func() { 112 cbWrapped(mkTextLogEntry([]line{ 113 {"w are you", "\n"}, 114 }, 2)) 115 So(values, ShouldResemble, []string{ 116 "hi!\n", 117 "there!\n", 118 "how are you!\n", 119 }) 120 So(seq, ShouldResemble, []uint64{0, 2}) 121 }) 122 123 Convey(`Flushes when called with niil`, func() { 124 cbWrapped(nil) 125 So(values, ShouldResemble, []string{ 126 "hi!\n", 127 "there!\n", 128 "ho!", 129 }) 130 So(seq, ShouldResemble, []uint64{0, 2}) 131 }) 132 }) 133 }) 134 }) 135 136 Convey(`Callback wrapper panics`, t, func() { 137 cbWrapped := mkWrappedTextCb(nil, nil) 138 139 Convey(`When called on non-text LogEntries`, func() { 140 So( 141 func() { 142 cbWrapped(&logpb.LogEntry{Content: &logpb.LogEntry_Datagram{}}) 143 }, 144 ShouldPanicLike, 145 "expected *logpb.LogEntry_Text", 146 ) 147 }) 148 149 Convey(`When the partial line is not in expected location`, func() { 150 Convey(`Like the first of multiple lines`, func() { 151 So( 152 func() { 153 cbWrapped(mkTextLogEntry([]line{ 154 {"w ar", ""}, 155 {"e yo", ""}, 156 }, 2)) 157 }, 158 ShouldPanicLike, 159 "partial line not last", 160 ) 161 }) 162 163 Convey(`Like interspersed with complete lines`, func() { 164 So( 165 func() { 166 cbWrapped(mkTextLogEntry([]line{ 167 {"w", "\n"}, 168 {"ar", ""}, 169 {"e you", "\n"}, 170 }, 2)) 171 }, 172 ShouldPanicLike, 173 "partial line not last", 174 ) 175 }) 176 }) 177 }) 178 }