kubecost_codecs_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. package kubecost
  2. import (
  3. "testing"
  4. "time"
  5. )
  6. func TestAllocation_BinaryEncoding(t *testing.T) {
  7. // TODO niko/etl
  8. }
  9. func TestAllocationSet_BinaryEncoding(t *testing.T) {
  10. // TODO niko/etl
  11. }
  12. func BenchmarkAllocationSetRange_BinaryEncoding(b *testing.B) {
  13. endYesterday := time.Now().UTC().Truncate(day)
  14. startYesterday := endYesterday.Add(-day)
  15. startD2 := startYesterday
  16. startD1 := startD2.Add(-day)
  17. startD0 := startD1.Add(-day)
  18. var asr0, asr1 *AllocationSetRange
  19. var bs []byte
  20. var err error
  21. asr0 = NewAllocationSetRange(
  22. generateAllocationSet(startD0),
  23. generateAllocationSet(startD1),
  24. generateAllocationSet(startD2),
  25. )
  26. for it := 0; it < b.N; it++ {
  27. bs, err = asr0.MarshalBinary()
  28. if err != nil {
  29. b.Fatalf("AllocationSetRange.Binary: unexpected error: %s", err)
  30. return
  31. }
  32. asr1 = &AllocationSetRange{}
  33. err = asr1.UnmarshalBinary(bs)
  34. if err != nil {
  35. b.Fatalf("AllocationSetRange.Binary: unexpected error: %s", err)
  36. return
  37. }
  38. if asr0.Length() != asr1.Length() {
  39. b.Fatalf("AllocationSetRange.Binary: expected %d; found %d", asr0.Length(), asr1.Length())
  40. }
  41. if !asr0.Window().Equal(asr1.Window()) {
  42. b.Fatalf("AllocationSetRange.Binary: expected %s; found %s", asr0.Window(), asr1.Window())
  43. }
  44. asr0.Each(func(i int, as0 *AllocationSet) {
  45. as1, err := asr1.Get(i)
  46. if err != nil {
  47. b.Fatalf("AllocationSetRange.Binary: unexpected error: %s", err)
  48. }
  49. if as0.Length() != as1.Length() {
  50. b.Fatalf("AllocationSetRange.Binary: expected %d; found %d", as0.Length(), as1.Length())
  51. }
  52. if !as0.Window.Equal(as1.Window) {
  53. b.Fatalf("AllocationSetRange.Binary: expected %s; found %s", as0.Window, as1.Window)
  54. }
  55. as0.Each(func(k string, a0 *Allocation) {
  56. a1 := as1.Get(k)
  57. if a1 == nil {
  58. b.Fatalf("AllocationSetRange.Binary: missing Allocation: %s", a0)
  59. }
  60. if !a0.Equal(a1) {
  61. b.Fatalf("AllocationSetRange.Binary: unequal Allocations \"%s\": expected %s; found %s", k, a0, a1)
  62. }
  63. })
  64. })
  65. }
  66. }
  67. func TestAllocationSetRange_BinaryEncoding(t *testing.T) {
  68. endYesterday := time.Now().UTC().Truncate(day)
  69. startYesterday := endYesterday.Add(-day)
  70. startD2 := startYesterday
  71. startD1 := startD2.Add(-day)
  72. startD0 := startD1.Add(-day)
  73. var asr0, asr1 *AllocationSetRange
  74. var bs []byte
  75. var err error
  76. asr0 = NewAllocationSetRange(
  77. generateAllocationSet(startD0),
  78. generateAllocationSet(startD1),
  79. generateAllocationSet(startD2),
  80. )
  81. bs, err = asr0.MarshalBinary()
  82. if err != nil {
  83. t.Fatalf("AllocationSetRange.Binary: unexpected error: %s", err)
  84. return
  85. }
  86. asr1 = &AllocationSetRange{}
  87. err = asr1.UnmarshalBinary(bs)
  88. if err != nil {
  89. t.Fatalf("AllocationSetRange.Binary: unexpected error: %s", err)
  90. return
  91. }
  92. if asr0.Length() != asr1.Length() {
  93. t.Fatalf("AllocationSetRange.Binary: expected %d; found %d", asr0.Length(), asr1.Length())
  94. }
  95. if !asr0.Window().Equal(asr1.Window()) {
  96. t.Fatalf("AllocationSetRange.Binary: expected %s; found %s", asr0.Window(), asr1.Window())
  97. }
  98. asr0.Each(func(i int, as0 *AllocationSet) {
  99. as1, err := asr1.Get(i)
  100. if err != nil {
  101. t.Fatalf("AllocationSetRange.Binary: unexpected error: %s", err)
  102. }
  103. if as0.Length() != as1.Length() {
  104. t.Fatalf("AllocationSetRange.Binary: expected %d; found %d", as0.Length(), as1.Length())
  105. }
  106. if !as0.Window.Equal(as1.Window) {
  107. t.Fatalf("AllocationSetRange.Binary: expected %s; found %s", as0.Window, as1.Window)
  108. }
  109. as0.Each(func(k string, a0 *Allocation) {
  110. a1 := as1.Get(k)
  111. if a1 == nil {
  112. t.Fatalf("AllocationSetRange.Binary: missing Allocation: %s", a0)
  113. }
  114. if !a0.Equal(a1) {
  115. t.Fatalf("AllocationSetRange.Binary: unequal Allocations \"%s\": expected %s; found %s", k, a0, a1)
  116. }
  117. })
  118. })
  119. }
  120. func TestAny_BinaryEncoding(t *testing.T) {
  121. start := time.Date(2020, time.September, 16, 0, 0, 0, 0, time.UTC)
  122. end := start.Add(24 * time.Hour)
  123. window := NewWindow(&start, &end)
  124. var a0, a1 *Any
  125. var bs []byte
  126. var err error
  127. a0 = NewAsset(*window.start, *window.end, window)
  128. a0.SetProperties(&AssetProperties{
  129. Name: "any1",
  130. Cluster: "cluster1",
  131. ProviderID: "世界",
  132. })
  133. a0.Cost = 123.45
  134. a0.SetAdjustment(1.23)
  135. bs, err = a0.MarshalBinary()
  136. if err != nil {
  137. t.Fatalf("Any.Binary: unexpected error: %s", err)
  138. }
  139. a1 = &Any{}
  140. err = a1.UnmarshalBinary(bs)
  141. if err != nil {
  142. t.Fatalf("Any.Binary: unexpected error: %s", err)
  143. }
  144. if a1.Properties().Name != a0.Properties().Name {
  145. t.Fatalf("Any.Binary: expected %s, found %s", a0.Properties().Name, a1.Properties().Name)
  146. }
  147. if a1.Properties().Cluster != a0.Properties().Cluster {
  148. t.Fatalf("Any.Binary: expected %s, found %s", a0.Properties().Cluster, a1.Properties().Cluster)
  149. }
  150. if a1.Properties().ProviderID != a0.Properties().ProviderID {
  151. t.Fatalf("Any.Binary: expected %s, found %s", a0.Properties().ProviderID, a1.Properties().ProviderID)
  152. }
  153. if a1.Adjustment() != a0.Adjustment() {
  154. t.Fatalf("Any.Binary: expected %f, found %f", a0.Adjustment(), a1.Adjustment())
  155. }
  156. if a1.TotalCost() != a0.TotalCost() {
  157. t.Fatalf("Any.Binary: expected %f, found %f", a0.TotalCost(), a1.TotalCost())
  158. }
  159. if !a1.Window().Equal(a0.Window()) {
  160. t.Fatalf("Any.Binary: expected %s, found %s", a0.Window(), a1.Window())
  161. }
  162. }
  163. func TestAsset_BinaryEncoding(t *testing.T) {
  164. // TODO niko/etl
  165. }
  166. func TestAssetSet_BinaryEncoding(t *testing.T) {
  167. // TODO niko/etl
  168. }
  169. func TestAssetSetRange_BinaryEncoding(t *testing.T) {
  170. endYesterday := time.Now().UTC().Truncate(day)
  171. startYesterday := endYesterday.Add(-day)
  172. startD2 := startYesterday
  173. startD1 := startD2.Add(-day)
  174. startD0 := startD1.Add(-day)
  175. var asr0, asr1 *AssetSetRange
  176. var bs []byte
  177. var err error
  178. asr0 = NewAssetSetRange(
  179. generateAssetSet(startD0),
  180. generateAssetSet(startD1),
  181. generateAssetSet(startD2),
  182. )
  183. bs, err = asr0.MarshalBinary()
  184. if err != nil {
  185. t.Fatalf("AssetSetRange.Binary: unexpected error: %s", err)
  186. return
  187. }
  188. asr1 = &AssetSetRange{}
  189. err = asr1.UnmarshalBinary(bs)
  190. if err != nil {
  191. t.Fatalf("AssetSetRange.Binary: unexpected error: %s", err)
  192. return
  193. }
  194. if asr0.Length() != asr1.Length() {
  195. t.Fatalf("AssetSetRange.Binary: expected %d; found %d", asr0.Length(), asr1.Length())
  196. }
  197. if !asr0.Window().Equal(asr1.Window()) {
  198. t.Fatalf("AssetSetRange.Binary: expected %s; found %s", asr0.Window(), asr1.Window())
  199. }
  200. asr0.Each(func(i int, as0 *AssetSet) {
  201. as1, err := asr1.Get(i)
  202. if err != nil {
  203. t.Fatalf("AssetSetRange.Binary: unexpected error: %s", err)
  204. }
  205. if as0.Length() != as1.Length() {
  206. t.Fatalf("AssetSetRange.Binary: expected %d; found %d", as0.Length(), as1.Length())
  207. }
  208. if !as0.Window.Equal(as1.Window) {
  209. t.Fatalf("AssetSetRange.Binary: expected %s; found %s", as0.Window, as1.Window)
  210. }
  211. as0.Each(func(k string, a0 Asset) {
  212. a1, ok := as1.Get(k)
  213. if !ok {
  214. t.Fatalf("AssetSetRange.Binary: missing Asset: %s", a0)
  215. }
  216. if !a0.Equal(a1) {
  217. t.Fatalf("AssetSetRange.Binary: unequal Assets \"%s\": expected %s; found %s", k, a0, a1)
  218. }
  219. })
  220. })
  221. }
  222. func TestBreakdown_BinaryEncoding(t *testing.T) {
  223. var b0, b1 *Breakdown
  224. var bs []byte
  225. var err error
  226. b0 = &Breakdown{
  227. Idle: 0.75,
  228. Other: 0.1,
  229. System: 0.0,
  230. User: 0.15,
  231. }
  232. bs, err = b0.MarshalBinary()
  233. if err != nil {
  234. t.Fatalf("Breakdown.Binary: unexpected error: %s", err)
  235. }
  236. b1 = &Breakdown{}
  237. err = b1.UnmarshalBinary(bs)
  238. if err != nil {
  239. t.Fatalf("Breakdown.Binary: unexpected error: %s", err)
  240. }
  241. if b1.Idle != b0.Idle {
  242. t.Fatalf("Breakdown.Binary: expected %f, found %f", b0.Idle, b1.Idle)
  243. }
  244. if b1.Other != b0.Other {
  245. t.Fatalf("Breakdown.Binary: expected %f, found %f", b0.Other, b1.Other)
  246. }
  247. if b1.System != b0.System {
  248. t.Fatalf("Breakdown.Binary: expected %f, found %f", b0.System, b1.System)
  249. }
  250. if b1.User != b0.User {
  251. t.Fatalf("Breakdown.Binary: expected %f, found %f", b0.User, b1.User)
  252. }
  253. }
  254. func TestCloudAny_BinaryEncoding(t *testing.T) {
  255. ws := time.Date(2020, time.September, 16, 0, 0, 0, 0, time.UTC)
  256. we := ws.Add(24 * time.Hour)
  257. window := NewWindow(&ws, &we)
  258. var a0, a1 *Cloud
  259. var bs []byte
  260. var err error
  261. a0 = NewCloud(ComputeCategory, "providerid1", *window.start, *window.end, window)
  262. a0.Cost = 6.09
  263. a0.SetAdjustment(-1.23)
  264. bs, err = a0.MarshalBinary()
  265. if err != nil {
  266. t.Fatalf("CloudAny.Binary: unexpected error: %s", err)
  267. }
  268. a1 = &Cloud{}
  269. err = a1.UnmarshalBinary(bs)
  270. if err != nil {
  271. t.Fatalf("CloudAny.Binary: unexpected error: %s", err)
  272. }
  273. if !a0.Equal(a1) {
  274. t.Fatalf("CloudAny.Binary: expected %v, found %v", a0, a1)
  275. }
  276. }
  277. func TestClusterManagement_BinaryEncoding(t *testing.T) {
  278. ws := time.Date(2020, time.September, 16, 0, 0, 0, 0, time.UTC)
  279. we := ws.Add(24 * time.Hour)
  280. window := NewWindow(&ws, &we)
  281. var a0, a1 *ClusterManagement
  282. var bs []byte
  283. var err error
  284. a0 = NewClusterManagement("aws", "cluster1", window)
  285. a0.Cost = 4.003
  286. a0.SetAdjustment(-3.23)
  287. bs, err = a0.MarshalBinary()
  288. if err != nil {
  289. t.Fatalf("ClusterManagement.Binary: unexpected error: %s", err)
  290. }
  291. a1 = &ClusterManagement{}
  292. err = a1.UnmarshalBinary(bs)
  293. if err != nil {
  294. t.Fatalf("ClusterManagement.Binary: unexpected error: %s", err)
  295. }
  296. if !a0.Equal(a1) {
  297. t.Fatalf("ClusterManagement.Binary: expected %v, found %v", a0, a1)
  298. }
  299. }
  300. func TestDisk_BinaryEncoding(t *testing.T) {
  301. ws := time.Date(2020, time.September, 16, 0, 0, 0, 0, time.UTC)
  302. we := ws.Add(24 * time.Hour)
  303. window := NewWindow(&ws, &we)
  304. hours := window.Duration().Hours()
  305. start := time.Date(2020, time.September, 16, 3, 0, 0, 0, time.UTC)
  306. end := time.Date(2020, time.September, 16, 15, 12, 0, 0, time.UTC)
  307. var a0, a1 *Disk
  308. var bs []byte
  309. var err error
  310. a0 = NewDisk("any1", "cluster1", "世界", start, end, window)
  311. a0.ByteHours = 100 * 1024 * 1024 * 1024 * hours
  312. a0.Cost = 4.003
  313. a0.Local = 0.4
  314. a0.Breakdown = &Breakdown{
  315. Idle: 0.9,
  316. Other: 0.05,
  317. System: 0.05,
  318. User: 0.0,
  319. }
  320. a0.SetAdjustment(-3.23)
  321. bs, err = a0.MarshalBinary()
  322. if err != nil {
  323. t.Fatalf("Disk.Binary: unexpected error: %s", err)
  324. }
  325. a1 = &Disk{}
  326. err = a1.UnmarshalBinary(bs)
  327. if err != nil {
  328. t.Fatalf("Disk.Binary: unexpected error: %s", err)
  329. }
  330. if !a0.Equal(a1) {
  331. t.Fatalf("Disk.Binary: expected %v, found %v", a0, a1)
  332. }
  333. }
  334. func TestNode_BinaryEncoding(t *testing.T) {
  335. ws := time.Date(2020, time.September, 16, 0, 0, 0, 0, time.UTC)
  336. we := ws.Add(24 * time.Hour)
  337. window := NewWindow(&ws, &we)
  338. hours := window.Duration().Hours()
  339. start := time.Date(2020, time.September, 16, 3, 0, 0, 0, time.UTC)
  340. end := time.Date(2020, time.September, 16, 15, 12, 0, 0, time.UTC)
  341. var a0, a1 *Node
  342. var bs []byte
  343. var err error
  344. a0 = NewNode("any1", "cluster1", "世界", start, end, window)
  345. a0.NodeType = "n2-standard"
  346. a0.Preemptible = 1.0
  347. a0.CPUCoreHours = 2.0 * hours
  348. a0.RAMByteHours = 12.0 * gb * hours
  349. a0.CPUCost = 1.50
  350. a0.GPUCost = 30.44
  351. a0.RAMCost = 15.0
  352. a0.Discount = 0.9
  353. a0.CPUBreakdown = &Breakdown{
  354. Idle: 0.9,
  355. Other: 0.05,
  356. System: 0.05,
  357. User: 0.0,
  358. }
  359. a0.RAMBreakdown = &Breakdown{
  360. Idle: 0.4,
  361. Other: 0.05,
  362. System: 0.05,
  363. User: 0.5,
  364. }
  365. a0.SetAdjustment(1.23)
  366. bs, err = a0.MarshalBinary()
  367. if err != nil {
  368. t.Fatalf("Node.Binary: unexpected error: %s", err)
  369. }
  370. a1 = &Node{}
  371. err = a1.UnmarshalBinary(bs)
  372. if err != nil {
  373. t.Fatalf("Node.Binary: unexpected error: %s", err)
  374. }
  375. if !a0.Equal(a1) {
  376. t.Fatalf("Node.Binary: expected %v, found %v", a0, a1)
  377. }
  378. }
  379. func TestProperties_BinaryEncoding(t *testing.T) {
  380. var p0, p1 *Properties
  381. var bs []byte
  382. var err error
  383. // empty properties
  384. p0 = &Properties{}
  385. bs, err = p0.MarshalBinary()
  386. if err != nil {
  387. t.Fatalf("Properties.Binary: unexpected error: %s", err)
  388. }
  389. p1 = &Properties{}
  390. err = p1.UnmarshalBinary(bs)
  391. if err != nil {
  392. t.Fatalf("Properties.Binary: unexpected error: %s", err)
  393. }
  394. if !p0.Equal(p1) {
  395. t.Fatalf("Properties.Binary: expected %s; found %s", p0, p1)
  396. }
  397. // complete properties
  398. p0 = &Properties{}
  399. p0.SetCluster("cluster1")
  400. p0.SetContainer("container-abc-1")
  401. p0.SetController("daemonset-abc")
  402. p0.SetControllerKind("daemonset")
  403. p0.SetNamespace("namespace1")
  404. p0.SetNode("node1")
  405. p0.SetPod("daemonset-abc-123")
  406. p0.SetLabels(map[string]string{
  407. "app": "cost-analyzer",
  408. "tier": "frontend",
  409. })
  410. p0.SetServices([]string{"kubecost-frontend"})
  411. bs, err = p0.MarshalBinary()
  412. if err != nil {
  413. t.Fatalf("Properties.Binary: unexpected error: %s", err)
  414. }
  415. p1 = &Properties{}
  416. err = p1.UnmarshalBinary(bs)
  417. if err != nil {
  418. t.Fatalf("Properties.Binary: unexpected error: %s", err)
  419. }
  420. if !p0.Equal(p1) {
  421. t.Fatalf("Properties.Binary: expected %s; found %s", p0, p1)
  422. }
  423. // incomplete properties
  424. p0 = &Properties{}
  425. p0.SetCluster("cluster1")
  426. p0.SetController("daemonset-abc")
  427. p0.SetControllerKind("daemonset")
  428. p0.SetNamespace("namespace1")
  429. p0.SetServices([]string{})
  430. bs, err = p0.MarshalBinary()
  431. if err != nil {
  432. t.Fatalf("Properties.Binary: unexpected error: %s", err)
  433. }
  434. p1 = &Properties{}
  435. err = p1.UnmarshalBinary(bs)
  436. if err != nil {
  437. t.Fatalf("Properties.Binary: unexpected error: %s", err)
  438. }
  439. if !p0.Equal(p1) {
  440. t.Fatalf("Properties.Binary: expected %s; found %s", p0, p1)
  441. }
  442. }
  443. func TestShared_BinaryEncoding(t *testing.T) {
  444. ws := time.Date(2020, time.September, 16, 0, 0, 0, 0, time.UTC)
  445. we := ws.Add(24 * time.Hour)
  446. window := NewWindow(&ws, &we)
  447. var a0, a1 *SharedAsset
  448. var bs []byte
  449. var err error
  450. a0 = NewSharedAsset("any1", window)
  451. a0.Cost = 4.04
  452. a0.SetAdjustment(1.23)
  453. bs, err = a0.MarshalBinary()
  454. if err != nil {
  455. t.Fatalf("SharedAsset.Binary: unexpected error: %s", err)
  456. }
  457. a1 = &SharedAsset{}
  458. err = a1.UnmarshalBinary(bs)
  459. if err != nil {
  460. t.Fatalf("SharedAsset.Binary: unexpected error: %s", err)
  461. }
  462. if !a0.Equal(a1) {
  463. t.Fatalf("SharedAsset.Binary: expected %v, found %v", a0, a1)
  464. }
  465. }
  466. func TestWindow_BinaryEncoding(t *testing.T) {
  467. var w0, w1 Window
  468. var bs []byte
  469. var err error
  470. // Window (nil, nil)
  471. w0 = NewWindow(nil, nil)
  472. bs, err = w0.MarshalBinary()
  473. if err != nil {
  474. t.Fatalf("Window.Binary: unexpected error: %s", err)
  475. }
  476. err = w1.UnmarshalBinary(bs)
  477. if err != nil {
  478. t.Fatalf("Window.Binary: unexpected error: %s", err)
  479. }
  480. if w1.Start() != w0.Start() {
  481. t.Fatalf("Window.Binary: expected %v; found %v", w0.Start(), w1.Start())
  482. }
  483. if w1.End() != w0.End() {
  484. t.Fatalf("Window.Binary: expected %v; found %v", w0.End(), w1.End())
  485. }
  486. // Window (time, nil)
  487. ts := time.Now()
  488. w0 = NewWindow(&ts, nil)
  489. bs, err = w0.MarshalBinary()
  490. if err != nil {
  491. t.Fatalf("Window.Binary: unexpected error: %s", err)
  492. }
  493. err = w1.UnmarshalBinary(bs)
  494. if err != nil {
  495. t.Fatalf("Window.Binary: unexpected error: %s", err)
  496. }
  497. if !w1.Start().Equal(*w0.Start()) {
  498. t.Fatalf("Window.Binary: expected %v; found %v", w0.Start(), w1.Start())
  499. }
  500. if w1.End() != w0.End() {
  501. t.Fatalf("Window.Binary: expected %v; found %v", w0.End(), w1.End())
  502. }
  503. // Window (nil, time)
  504. te := time.Now()
  505. w0 = NewWindow(nil, &te)
  506. bs, err = w0.MarshalBinary()
  507. if err != nil {
  508. t.Fatalf("Window.Binary: unexpected error: %s", err)
  509. }
  510. err = w1.UnmarshalBinary(bs)
  511. if err != nil {
  512. t.Fatalf("Window.Binary: unexpected error: %s", err)
  513. }
  514. if w1.Start() != w0.Start() {
  515. t.Fatalf("Window.Binary: expected %v; found %v", w0.Start(), w1.Start())
  516. }
  517. if !w1.End().Equal(*w0.End()) {
  518. t.Fatalf("Window.Binary: expected %v; found %v", w0.End(), w1.End())
  519. }
  520. // Window (time, time)
  521. ts, te = time.Now(), time.Now()
  522. w0 = NewWindow(&ts, &te)
  523. bs, err = w0.MarshalBinary()
  524. if err != nil {
  525. t.Fatalf("Window.Binary: unexpected error: %s", err)
  526. }
  527. err = w1.UnmarshalBinary(bs)
  528. if err != nil {
  529. t.Fatalf("Window.Binary: unexpected error: %s", err)
  530. }
  531. if !w1.Start().Equal(*w0.Start()) {
  532. t.Fatalf("Window.Binary: expected %v; found %v", w0.Start(), w1.Start())
  533. }
  534. if !w1.End().Equal(*w0.End()) {
  535. t.Fatalf("Window.Binary: expected %v; found %v", w0.End(), w1.End())
  536. }
  537. }