github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/tests/models/entity_test.go (about) 1 // This file is part of the Smart Home 2 // Program complex distribution https://github.com/e154/smart-home 3 // Copyright (C) 2016-2023, Filippov Alex 4 // 5 // This library is free software: you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 3 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Library General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library. If not, see 17 // <https://www.gnu.org/licenses/>. 18 19 package models 20 21 import ( 22 "context" 23 "testing" 24 25 "github.com/e154/smart-home/adaptors" 26 "github.com/e154/smart-home/common" 27 m "github.com/e154/smart-home/models" 28 "github.com/e154/smart-home/system/access_list" 29 "github.com/e154/smart-home/system/migrations" 30 . "github.com/smartystreets/goconvey/convey" 31 ) 32 33 func TestEntity(t *testing.T) { 34 Convey("entity", t, func(ctx C) { 35 err := container.Invoke(func(adaptors *adaptors.Adaptors, 36 migrations *migrations.Migrations, 37 accessList access_list.AccessListService) { 38 39 // clear database 40 _ = migrations.Purge() 41 42 // add scripts 43 script1 := &m.Script{ 44 Lang: common.ScriptLangCoffee, 45 Name: "script1", 46 Source: "print 'OK'", 47 } 48 script2 := &m.Script{ 49 Lang: common.ScriptLangCoffee, 50 Name: "script2", 51 Source: "print 'OK'", 52 } 53 var err error 54 script1.Id, err = adaptors.Script.Add(context.Background(), script1) 55 So(err, ShouldBeNil) 56 script2.Id, err = adaptors.Script.Add(context.Background(), script2) 57 So(err, ShouldBeNil) 58 59 // plugins 60 err = AddPlugin(adaptors, "sensor") 61 So(err, ShouldBeNil) 62 63 // add image 64 image1 := &m.Image{ 65 Url: "foo", 66 Name: "foo", 67 } 68 image2 := &m.Image{ 69 Url: "bar", 70 Name: "bar", 71 } 72 image1.Id, err = adaptors.Image.Add(context.Background(), image1) 73 So(err, ShouldBeNil) 74 image2.Id, err = adaptors.Image.Add(context.Background(), image2) 75 So(err, ShouldBeNil) 76 77 t.Run("Create", func(t *testing.T) { 78 Convey("", t, func(ctx C) { 79 // entity 80 entity := &m.Entity{ 81 Id: common.EntityId("sensor.entity1"), 82 PluginName: "sensor", 83 AutoLoad: true, 84 ImageId: common.Int64(image1.Id), 85 Scripts: []*m.Script{ 86 script1, 87 }, 88 Actions: []*m.EntityAction{ 89 { 90 Name: "ACTION1", 91 ScriptId: common.Int64(script1.Id), 92 ImageId: common.Int64(image2.Id), 93 }, 94 }, 95 States: []*m.EntityState{ 96 { 97 Name: "STATE1", 98 }, 99 }, 100 Metrics: []*m.Metric{ 101 { 102 Name: "bar", 103 Description: "bar", 104 Options: m.MetricOptions{ 105 Items: []m.MetricOptionsItem{ 106 { 107 Name: "foo", 108 Description: "foo", 109 Color: "foo", 110 Translate: "foo", 111 Label: "foo", 112 }, 113 }, 114 }, 115 }, 116 }, 117 Attributes: NetAttr(), 118 Settings: NetSettings(), 119 Tags: []*m.Tag{ 120 {Name: "foo"}, 121 }, 122 } 123 err = adaptors.Entity.Add(context.Background(), entity) 124 So(err, ShouldBeNil) 125 126 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 127 So(err, ShouldBeNil) 128 129 So(entity.AutoLoad, ShouldBeTrue) 130 So(len(entity.Actions), ShouldEqual, 1) 131 So(entity.Actions[0].Name, ShouldEqual, "ACTION1") 132 So(entity.Actions[0].Image, ShouldNotBeNil) 133 So(entity.Actions[0].Image.Name, ShouldEqual, "bar") 134 So(entity.Image, ShouldNotBeNil) 135 So(entity.Image.Name, ShouldEqual, "foo") 136 So(len(entity.States), ShouldEqual, 1) 137 So(entity.States[0].Name, ShouldEqual, "STATE1") 138 So(len(entity.Scripts), ShouldEqual, 1) 139 So(entity.Scripts[0].Name, ShouldEqual, "script1") 140 So(len(entity.Metrics), ShouldEqual, 1) 141 So(len(entity.Tags), ShouldEqual, 1) 142 So(entity.Tags[0].Name, ShouldEqual, "foo") 143 So(entity.Metrics[0].Name, ShouldEqual, "bar") 144 So(entity.Metrics[0].Options.Items[0].Name, ShouldEqual, "foo") 145 So(entity.Settings, ShouldNotBeEmpty) 146 So(entity.Settings["s"].String(), ShouldEqual, "s") 147 So(entity.Attributes, ShouldNotBeEmpty) 148 So(entity.Attributes["s"].Name, ShouldEqual, "s") 149 So(entity.Attributes["s"].String(), ShouldEqual, "") 150 }) 151 }) 152 153 t.Run("Update", func(t *testing.T) { 154 Convey("", t, func(ctx C) { 155 // entity 156 entity := &m.Entity{ 157 Id: common.EntityId("sensor.entity1"), 158 AutoLoad: true, 159 PluginName: "sensor", 160 Scripts: []*m.Script{ 161 script2, 162 }, 163 Actions: []*m.EntityAction{ 164 { 165 Name: "ACTION2", 166 ScriptId: common.Int64(script1.Id), 167 }, 168 }, 169 States: []*m.EntityState{ 170 { 171 Name: "STATE2", 172 }, 173 }, 174 Metrics: []*m.Metric{ 175 { 176 Name: "bar2", 177 Description: "bar2", 178 Options: m.MetricOptions{ 179 Items: []m.MetricOptionsItem{ 180 { 181 Name: "foo2", 182 Description: "foo2", 183 Color: "foo2", 184 Translate: "foo2", 185 Label: "foo2", 186 }, 187 }, 188 }, 189 }, 190 }, 191 Tags: []*m.Tag{ 192 {Name: "bar"}, 193 }, 194 } 195 err = adaptors.Entity.Update(context.Background(), entity) 196 So(err, ShouldBeNil) 197 198 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 199 So(err, ShouldBeNil) 200 201 So(len(entity.Actions), ShouldEqual, 1) 202 So(entity.Actions[0].Name, ShouldEqual, "ACTION2") 203 So(len(entity.States), ShouldEqual, 1) 204 So(entity.States[0].Name, ShouldEqual, "STATE2") 205 So(len(entity.Scripts), ShouldEqual, 1) 206 So(entity.Scripts[0].Name, ShouldEqual, "script2") 207 So(len(entity.Tags), ShouldEqual, 1) 208 So(entity.Tags[0].Name, ShouldEqual, "bar") 209 So(len(entity.Metrics), ShouldEqual, 1) 210 So(entity.Metrics[0].Name, ShouldEqual, "bar2") 211 So(entity.Metrics[0].Options.Items[0].Name, ShouldEqual, "foo2") 212 213 // v2 214 entity.Actions = []*m.EntityAction{} 215 entity.Tags = nil 216 217 err = adaptors.Entity.Update(context.Background(), entity) 218 So(err, ShouldBeNil) 219 220 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 221 So(err, ShouldBeNil) 222 223 So(len(entity.Actions), ShouldEqual, 0) 224 So(len(entity.States), ShouldEqual, 1) 225 So(entity.States[0].Name, ShouldEqual, "STATE2") 226 So(len(entity.Scripts), ShouldEqual, 1) 227 So(entity.Scripts[0].Name, ShouldEqual, "script2") 228 So(len(entity.Tags), ShouldEqual, 0) 229 So(len(entity.Metrics), ShouldEqual, 1) 230 So(entity.Metrics[0].Name, ShouldEqual, "bar2") 231 So(entity.Metrics[0].Options.Items[0].Name, ShouldEqual, "foo2") 232 233 // v3 234 entity.Actions = []*m.EntityAction{ 235 { 236 Name: "ACTION2", 237 ScriptId: common.Int64(script1.Id), 238 }, 239 } 240 entity.States = []*m.EntityState{} 241 err = adaptors.Entity.Update(context.Background(), entity) 242 So(err, ShouldBeNil) 243 244 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 245 So(err, ShouldBeNil) 246 247 So(len(entity.Actions), ShouldEqual, 1) 248 So(entity.Actions[0].Name, ShouldEqual, "ACTION2") 249 So(len(entity.States), ShouldEqual, 0) 250 So(len(entity.Scripts), ShouldEqual, 1) 251 So(entity.Scripts[0].Name, ShouldEqual, "script2") 252 So(len(entity.Metrics), ShouldEqual, 1) 253 So(entity.Metrics[0].Name, ShouldEqual, "bar2") 254 So(entity.Metrics[0].Options.Items[0].Name, ShouldEqual, "foo2") 255 256 // v4 257 entity.Actions = []*m.EntityAction{} 258 entity.States = []*m.EntityState{} 259 entity.Scripts = []*m.Script{ 260 script1, 261 script2, 262 } 263 err = adaptors.Entity.Update(context.Background(), entity) 264 So(err, ShouldBeNil) 265 266 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 267 So(err, ShouldBeNil) 268 269 So(len(entity.Actions), ShouldEqual, 0) 270 So(len(entity.States), ShouldEqual, 0) 271 So(len(entity.Scripts), ShouldEqual, 2) 272 So(len(entity.Metrics), ShouldEqual, 1) 273 So(entity.Metrics[0].Name, ShouldEqual, "bar2") 274 So(entity.Metrics[0].Options.Items[0].Name, ShouldEqual, "foo2") 275 276 // v5 277 entity.Actions = []*m.EntityAction{} 278 entity.States = []*m.EntityState{} 279 entity.Scripts = []*m.Script{} 280 entity.Metrics = []*m.Metric{} 281 282 err = adaptors.Entity.Update(context.Background(), entity) 283 So(err, ShouldBeNil) 284 285 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 286 So(err, ShouldBeNil) 287 288 So(len(entity.Actions), ShouldEqual, 0) 289 So(len(entity.States), ShouldEqual, 0) 290 So(len(entity.Scripts), ShouldEqual, 0) 291 So(len(entity.Metrics), ShouldEqual, 0) 292 293 // v5 294 entity.Actions = []*m.EntityAction{} 295 entity.States = []*m.EntityState{} 296 entity.Scripts = []*m.Script{} 297 entity.Metrics = []*m.Metric{ 298 { 299 Name: "bar4", 300 Description: "bar4", 301 Options: m.MetricOptions{ 302 Items: []m.MetricOptionsItem{ 303 { 304 Name: "foo4", 305 Description: "foo4", 306 Color: "foo4", 307 Translate: "foo4", 308 Label: "foo4", 309 }, 310 }, 311 }, 312 }, 313 } 314 315 err = adaptors.Entity.Update(context.Background(), entity) 316 So(err, ShouldBeNil) 317 318 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 319 So(err, ShouldBeNil) 320 321 So(len(entity.Actions), ShouldEqual, 0) 322 So(len(entity.States), ShouldEqual, 0) 323 So(len(entity.Scripts), ShouldEqual, 0) 324 So(len(entity.Metrics), ShouldEqual, 1) 325 So(entity.Metrics[0].Name, ShouldEqual, "bar4") 326 So(entity.Metrics[0].Options.Items[0].Name, ShouldEqual, "foo4") 327 }) 328 }) 329 330 t.Run("Import", func(t *testing.T) { 331 Convey("", t, func(ctx C) { 332 // entity 333 entity := &m.Entity{ 334 Id: common.EntityId("sensor.entity2"), 335 PluginName: "sensor", 336 Scripts: []*m.Script{ 337 { 338 Id: 456, 339 Lang: common.ScriptLangCoffee, 340 Name: "script3", 341 Source: "print 'OK'", 342 }, 343 { 344 Id: 789, 345 Lang: common.ScriptLangCoffee, 346 Name: "script2", 347 Source: "print 'OK'", 348 }, 349 }, 350 Actions: []*m.EntityAction{ 351 { 352 Id: 123, 353 Name: "ACTION3", 354 Description: "ACTION3", 355 Script: &m.Script{ 356 Id: 456, 357 Lang: common.ScriptLangCoffee, 358 Name: "script3", 359 Source: "print 'OK'", 360 }, 361 }, 362 }, 363 States: []*m.EntityState{ 364 { 365 Id: 123, 366 Description: "STATE3", 367 Name: "STATE3", 368 }, 369 }, 370 Metrics: []*m.Metric{ 371 { 372 Name: "bar3", 373 Description: "bar3", 374 Options: m.MetricOptions{ 375 Items: []m.MetricOptionsItem{ 376 { 377 Name: "foo3", 378 Description: "foo3", 379 Color: "foo3", 380 Translate: "foo3", 381 Label: "foo3", 382 }, 383 }, 384 }, 385 }, 386 }, 387 Tags: []*m.Tag{ 388 {Name: "foo"}, 389 {Name: "bar"}, 390 }, 391 } 392 err = adaptors.Entity.Import(context.Background(), entity) 393 So(err, ShouldBeNil) 394 395 entity, err = adaptors.Entity.GetById(context.Background(), entity.Id) 396 So(err, ShouldBeNil) 397 398 So(len(entity.Actions), ShouldEqual, 1) 399 So(entity.Actions[0].Name, ShouldEqual, "ACTION3") 400 So(len(entity.States), ShouldEqual, 1) 401 So(entity.States[0].Name, ShouldEqual, "STATE3") 402 So(len(entity.Scripts), ShouldEqual, 2) 403 So(entity.Scripts[0].Name, ShouldEqual, "script2") 404 So(entity.Scripts[1].Name, ShouldEqual, "script3") 405 So(len(entity.Tags), ShouldEqual, 2) 406 So(entity.Tags[0].Name, ShouldEqual, "foo") 407 So(entity.Tags[1].Name, ShouldEqual, "bar") 408 So(len(entity.Metrics), ShouldEqual, 1) 409 So(entity.Metrics[0].Name, ShouldEqual, "bar3") 410 So(entity.Metrics[0].Options.Items[0].Name, ShouldEqual, "foo3") 411 412 entity3 := &m.Entity{ 413 Id: common.EntityId("sensor.entity3"), 414 PluginName: "sensor", 415 Scripts: []*m.Script{}, 416 Actions: []*m.EntityAction{}, 417 States: []*m.EntityState{}, 418 Metrics: []*m.Metric{}, 419 Attributes: NetAttr(), 420 Settings: NetSettings(), 421 } 422 err = adaptors.Entity.Import(context.Background(), entity3) 423 So(err, ShouldBeNil) 424 425 entity, err = adaptors.Entity.GetById(context.Background(), entity3.Id) 426 So(err, ShouldBeNil) 427 428 So(len(entity.Actions), ShouldEqual, 0) 429 So(len(entity.States), ShouldEqual, 0) 430 So(len(entity.Scripts), ShouldEqual, 0) 431 So(len(entity.Metrics), ShouldEqual, 0) 432 So(len(entity.Tags), ShouldEqual, 0) 433 So(entity.Settings, ShouldNotBeEmpty) 434 So(entity.Settings["s"].String(), ShouldEqual, "s") 435 So(entity.Attributes, ShouldNotBeEmpty) 436 So(entity.Attributes["s"].Name, ShouldEqual, "s") 437 So(entity.Attributes["s"].String(), ShouldEqual, "") 438 439 err = adaptors.Entity.Import(context.Background(), entity3) 440 So(err, ShouldNotBeNil) 441 }) 442 }) 443 444 t.Run("Delete", func(t *testing.T) { 445 Convey("", t, func(ctx C) { 446 err = adaptors.Entity.Delete(context.Background(), "sensor.entity2") 447 So(err, ShouldBeNil) 448 449 err = adaptors.Entity.Delete(context.Background(), "sensor.entity2") 450 So(err, ShouldBeNil) 451 452 }) 453 }) 454 455 t.Run("List", func(t *testing.T) { 456 Convey("", t, func(ctx C) { 457 list, total, err := adaptors.Entity.List(context.Background(), 5, 0, "desc", "id", false, nil, nil, nil) 458 So(err, ShouldBeNil) 459 So(total, ShouldEqual, 2) 460 So(len(list), ShouldEqual, 2) 461 }) 462 }) 463 464 t.Run("Search", func(t *testing.T) { 465 Convey("", t, func(ctx C) { 466 467 list, total, err := adaptors.Entity.Search(context.Background(), "entity23", 5, 0) 468 So(err, ShouldBeNil) 469 So(total, ShouldEqual, 0) 470 So(len(list), ShouldEqual, 0) 471 472 list, total, err = adaptors.Entity.Search(context.Background(), "entity", 5, 0) 473 So(err, ShouldBeNil) 474 So(total, ShouldEqual, 2) 475 So(len(list), ShouldEqual, 2) 476 477 list, total, err = adaptors.Entity.Search(context.Background(), "entity1", 5, 0) 478 So(err, ShouldBeNil) 479 So(total, ShouldEqual, 1) 480 So(len(list), ShouldEqual, 1) 481 }) 482 }) 483 484 t.Run("GetById", func(t *testing.T) { 485 Convey("", t, func(ctx C) { 486 487 _, err := adaptors.Entity.GetById(context.Background(), "sensor.entity23", false) 488 So(err, ShouldNotBeNil) 489 490 entity, err := adaptors.Entity.GetById(context.Background(), "sensor.entity1", false) 491 So(err, ShouldBeNil) 492 So(entity.Id, ShouldEqual, "sensor.entity1") 493 }) 494 }) 495 496 t.Run("GetByIds", func(t *testing.T) { 497 Convey("", t, func(ctx C) { 498 499 list, err := adaptors.Entity.GetByIds(context.Background(), []common.EntityId{"sensor.entity23"}, false) 500 So(err, ShouldBeNil) 501 So(len(list), ShouldEqual, 0) 502 503 list, err = adaptors.Entity.GetByIds(context.Background(), []common.EntityId{"sensor.entity1"}, false) 504 So(err, ShouldBeNil) 505 So(list[0].Id, ShouldEqual, "sensor.entity1") 506 }) 507 }) 508 509 t.Run("GetByType", func(t *testing.T) { 510 Convey("", t, func(ctx C) { 511 512 list, err := adaptors.Entity.GetByType(context.Background(), "foo", 5, 0) 513 So(err, ShouldBeNil) 514 So(len(list), ShouldEqual, 0) 515 516 list, err = adaptors.Entity.GetByType(context.Background(), "sensor", 5, 0) 517 So(err, ShouldBeNil) 518 So(len(list), ShouldEqual, 1) 519 }) 520 }) 521 522 t.Run("UpdateAutoload", func(t *testing.T) { 523 Convey("", t, func(ctx C) { 524 525 err := adaptors.Entity.UpdateAutoload(context.Background(), "sensor.entity1", false) 526 So(err, ShouldBeNil) 527 528 entity, err := adaptors.Entity.GetById(context.Background(), "sensor.entity1", false) 529 So(err, ShouldBeNil) 530 So(entity.AutoLoad, ShouldEqual, false) 531 532 err = adaptors.Entity.UpdateAutoload(context.Background(), "sensor.entity1", true) 533 So(err, ShouldBeNil) 534 535 entity, err = adaptors.Entity.GetById(context.Background(), "sensor.entity1", false) 536 So(err, ShouldBeNil) 537 So(entity.AutoLoad, ShouldEqual, true) 538 }) 539 }) 540 541 }) 542 So(err, ShouldBeNil) 543 }) 544 }