controller_test.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package exporter
  2. import (
  3. "fmt"
  4. "sync/atomic"
  5. "testing"
  6. "time"
  7. "github.com/opencost/opencost/core/pkg/opencost"
  8. "github.com/opencost/opencost/core/pkg/util"
  9. )
  10. type TObject struct {
  11. Window opencost.Window
  12. Message string
  13. }
  14. func (tobj *TObject) MarshalBinary() ([]byte, error) {
  15. ctx := &opencost.EncodingContext{
  16. Buffer: util.NewBuffer(),
  17. Table: nil,
  18. }
  19. err := tobj.Window.MarshalBinaryWithContext(ctx)
  20. if err != nil {
  21. return nil, err
  22. }
  23. ctx.Buffer.WriteString(tobj.Message)
  24. return ctx.Buffer.Bytes(), nil
  25. }
  26. func (tobj *TObject) UnmarshalBinary(data []byte) error {
  27. ctx := &opencost.DecodingContext{
  28. Buffer: util.NewBufferFromBytes(data),
  29. Table: nil,
  30. }
  31. err := tobj.Window.UnmarshalBinaryWithContext(ctx)
  32. if err != nil {
  33. return err
  34. }
  35. tobj.Message = ctx.Buffer.ReadString()
  36. return nil
  37. }
  38. func (tobj *TObject) IsEmpty() bool {
  39. return tobj.Message == ""
  40. }
  41. type TObjectSource struct {
  42. count atomic.Uint64
  43. }
  44. func (s *TObjectSource) CanCompute(start, end time.Time) bool {
  45. return true
  46. }
  47. func (s *TObjectSource) Compute(start, end time.Time, resolution time.Duration) (*TObject, error) {
  48. c := s.count.Add(1)
  49. return &TObject{
  50. Window: opencost.NewClosedWindow(start, end),
  51. Message: fmt.Sprintf("Message #%d", c),
  52. }, nil
  53. }
  54. func (s *TObjectSource) Name() string {
  55. return "TObjectSource"
  56. }
  57. type TObjectComputeExporter struct {
  58. encoder Encoder[TObject]
  59. data map[string][]byte
  60. }
  61. func NewTObjectComputeExporter() *TObjectComputeExporter {
  62. return &TObjectComputeExporter{
  63. encoder: NewBingenEncoder[TObject](),
  64. data: make(map[string][]byte),
  65. }
  66. }
  67. func (t *TObjectComputeExporter) Export(window opencost.Window, data *TObject) error {
  68. d, err := data.MarshalBinary()
  69. if err != nil {
  70. return err
  71. }
  72. t.data[window.String()] = d
  73. return nil
  74. }
  75. func TestTObjectSymmetry(t *testing.T) {
  76. now := time.Now().UTC().Truncate(time.Hour)
  77. future := now.Add(time.Hour)
  78. tobj := &TObject{
  79. Window: opencost.NewClosedWindow(now, future),
  80. Message: "Testing 1 2 3",
  81. }
  82. data, err := tobj.MarshalBinary()
  83. if err != nil {
  84. t.Fatalf("Failed to marshal: %v", err)
  85. }
  86. tobj2 := &TObject{}
  87. err = tobj2.UnmarshalBinary(data)
  88. if err != nil {
  89. t.Fatalf("Failed to unmarshal: %v", err)
  90. }
  91. if tobj2.Message != tobj.Message && tobj2.Message == "Testing 1 2 3" {
  92. t.Fatalf("Message mismatch: %s != %s", tobj2.Message, tobj.Message)
  93. }
  94. if !tobj2.Window.Start().Equal(*tobj.Window.Start()) || !tobj2.Window.Start().Equal(now) {
  95. t.Fatalf("Start time mismatch: %s != %s", tobj2.Window.Start(), tobj.Window.Start())
  96. }
  97. if !tobj2.Window.End().Equal(*tobj.Window.End()) || !tobj2.Window.End().Equal(future) {
  98. t.Fatalf("End time mismatch: %s != %s", tobj2.Window.End(), tobj.Window.End())
  99. }
  100. }