github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/gnorkle/feeds/static/feed_test.gno (about) 1 package static_test 2 3 import ( 4 "errors" 5 "testing" 6 7 "gno.land/p/demo/gnorkle/feed" 8 "gno.land/p/demo/gnorkle/feeds/static" 9 "gno.land/p/demo/gnorkle/gnorkle" 10 "gno.land/p/demo/gnorkle/ingester" 11 "gno.land/p/demo/gnorkle/message" 12 "gno.land/p/demo/gnorkle/storage/simple" 13 ) 14 15 type mockIngester struct { 16 canAutoCommit bool 17 ingestErr error 18 commitErr error 19 value string 20 providerAddress string 21 } 22 23 func (i mockIngester) Type() ingester.Type { 24 return ingester.Type(0) 25 } 26 27 func (i *mockIngester) Ingest(value, providerAddress string) (bool, error) { 28 if i.ingestErr != nil { 29 return false, i.ingestErr 30 } 31 32 i.value = value 33 i.providerAddress = providerAddress 34 return i.canAutoCommit, nil 35 } 36 37 func (i *mockIngester) CommitValue(storage gnorkle.Storage, providerAddress string) error { 38 if i.commitErr != nil { 39 return i.commitErr 40 } 41 42 return storage.Put(i.value) 43 } 44 45 func TestNewSingleValueFeed(t *testing.T) { 46 staticFeed := static.NewSingleValueFeed("1", "") 47 if staticFeed.ID() != "1" { 48 t.Errorf("expected ID to be 1, got %s", staticFeed.ID()) 49 } 50 51 if staticFeed.Type() != feed.TypeStatic { 52 t.Errorf("expected static feed type, got %s", staticFeed.Type()) 53 } 54 } 55 56 func TestFeed_Ingest(t *testing.T) { 57 var undefinedFeed *static.Feed 58 if undefinedFeed.Ingest("", "", "") != feed.ErrUndefined { 59 t.Errorf("expected ErrUndefined, got nil") 60 } 61 62 tests := []struct { 63 name string 64 ingester *mockIngester 65 verifyIsLocked bool 66 doCommit bool 67 funcType message.FuncType 68 msg string 69 providerAddress string 70 expFeedValueString string 71 expErrText string 72 expIsActive bool 73 }{ 74 { 75 name: "func invalid error", 76 ingester: &mockIngester{}, 77 funcType: message.FuncType("derp"), 78 expErrText: "invalid message function derp", 79 expIsActive: true, 80 }, 81 { 82 name: "func ingest ingest error", 83 ingester: &mockIngester{ 84 ingestErr: errors.New("ingest error"), 85 }, 86 funcType: message.FuncTypeIngest, 87 expErrText: "ingest error", 88 expIsActive: true, 89 }, 90 { 91 name: "func ingest commit error", 92 ingester: &mockIngester{ 93 commitErr: errors.New("commit error"), 94 canAutoCommit: true, 95 }, 96 funcType: message.FuncTypeIngest, 97 expErrText: "commit error", 98 expIsActive: true, 99 }, 100 { 101 name: "func commit commit error", 102 ingester: &mockIngester{ 103 commitErr: errors.New("commit error"), 104 canAutoCommit: true, 105 }, 106 funcType: message.FuncTypeCommit, 107 expErrText: "commit error", 108 expIsActive: true, 109 }, 110 { 111 name: "only ingest", 112 ingester: &mockIngester{}, 113 funcType: message.FuncTypeIngest, 114 msg: "still active feed", 115 providerAddress: "gno1234", 116 expIsActive: true, 117 }, 118 { 119 name: "ingest autocommit", 120 ingester: &mockIngester{canAutoCommit: true}, 121 funcType: message.FuncTypeIngest, 122 msg: "still active feed", 123 providerAddress: "gno1234", 124 expFeedValueString: "still active feed", 125 verifyIsLocked: true, 126 }, 127 { 128 name: "commit no value", 129 ingester: &mockIngester{}, 130 funcType: message.FuncTypeCommit, 131 msg: "shouldn't be stored", 132 verifyIsLocked: true, 133 }, 134 { 135 name: "ingest then commmit", 136 ingester: &mockIngester{}, 137 funcType: message.FuncTypeIngest, 138 msg: "blahblah", 139 doCommit: true, 140 expFeedValueString: "blahblah", 141 verifyIsLocked: true, 142 }, 143 } 144 145 for _, tt := range tests { 146 t.Run(tt.name, func(t *testing.T) { 147 staticFeed := static.NewFeed( 148 "1", 149 "string", 150 tt.ingester, 151 simple.NewStorage(1), 152 nil, 153 ) 154 155 var errText string 156 if err := staticFeed.Ingest(tt.funcType, tt.msg, tt.providerAddress); err != nil { 157 errText = err.Error() 158 } 159 160 if errText != tt.expErrText { 161 t.Fatalf("expected error text %s, got %s", tt.expErrText, errText) 162 } 163 164 if tt.doCommit { 165 err := staticFeed.Ingest(message.FuncTypeCommit, "", "") 166 if err != nil { 167 t.Fatalf("follow up commit failed: %s", err.Error()) 168 } 169 } 170 171 if tt.verifyIsLocked { 172 errText = "" 173 if err := staticFeed.Ingest(tt.funcType, tt.msg, tt.providerAddress); err != nil { 174 errText = err.Error() 175 } 176 177 if errText != "feed locked" { 178 t.Fatalf("expected error text feed locked, got %s", errText) 179 } 180 } 181 182 if tt.ingester.providerAddress != tt.providerAddress { 183 t.Errorf("expected provider address %s, got %s", tt.providerAddress, tt.ingester.providerAddress) 184 } 185 186 feedValue, dataType, isLocked := staticFeed.Value() 187 if feedValue.String != tt.expFeedValueString { 188 t.Errorf("expected feed value string %s, got %s", tt.expFeedValueString, feedValue.String) 189 } 190 191 if dataType != "string" { 192 t.Errorf("expected data type string, got %s", dataType) 193 } 194 195 if isLocked != tt.verifyIsLocked { 196 t.Errorf("expected is locked %t, got %t", tt.verifyIsLocked, isLocked) 197 } 198 199 if staticFeed.IsActive() != tt.expIsActive { 200 t.Errorf("expected is active %t, got %t", tt.expIsActive, staticFeed.IsActive()) 201 } 202 }) 203 } 204 } 205 206 type mockTask struct { 207 err error 208 value string 209 } 210 211 func (t mockTask) MarshalJSON() ([]byte, error) { 212 if t.err != nil { 213 return nil, t.err 214 } 215 216 return []byte(`{"value":"` + t.value + `"}`), nil 217 } 218 219 func TestFeed_Tasks(t *testing.T) { 220 id := "99" 221 valueDataType := "int" 222 223 tests := []struct { 224 name string 225 tasks []feed.Task 226 expErrText string 227 expJSON string 228 }{ 229 { 230 name: "no tasks", 231 expJSON: `{"id":"99","type":"0","value_type":"int","tasks":[]}`, 232 }, 233 { 234 name: "marshal error", 235 tasks: []feed.Task{ 236 mockTask{err: errors.New("marshal error")}, 237 }, 238 expErrText: "marshal error", 239 }, 240 { 241 name: "one task", 242 tasks: []feed.Task{ 243 mockTask{value: "single"}, 244 }, 245 expJSON: `{"id":"99","type":"0","value_type":"int","tasks":[{"value":"single"}]}`, 246 }, 247 { 248 name: "two tasks", 249 tasks: []feed.Task{ 250 mockTask{value: "first"}, 251 mockTask{value: "second"}, 252 }, 253 expJSON: `{"id":"99","type":"0","value_type":"int","tasks":[{"value":"first"},{"value":"second"}]}`, 254 }, 255 } 256 257 for _, tt := range tests { 258 t.Run(tt.name, func(t *testing.T) { 259 staticFeed := static.NewSingleValueFeed( 260 id, 261 valueDataType, 262 tt.tasks..., 263 ) 264 265 if len(staticFeed.Tasks()) != len(tt.tasks) { 266 t.Fatalf("expected %d tasks, got %d", len(tt.tasks), len(staticFeed.Tasks())) 267 } 268 269 var errText string 270 json, err := staticFeed.MarshalJSON() 271 if err != nil { 272 errText = err.Error() 273 } 274 275 if errText != tt.expErrText { 276 t.Fatalf("expected error text %s, got %s", tt.expErrText, errText) 277 } 278 279 if string(json) != tt.expJSON { 280 t.Errorf("expected json %s, got %s", tt.expJSON, string(json)) 281 } 282 }) 283 } 284 }