blob: d1d57d210984aa756a6859fcdfc1da24a2e1d97d [file]
// Copyright 2020 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package migrator
import (
"bytes"
"encoding/csv"
"testing"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func mkReport(row ...string) *Report {
ret, err := NewReportFromCSVRow(row)
So(err, ShouldBeNil)
return ret
}
func TestReportDump(t *testing.T) {
t.Parallel()
Convey(`ReportDump`, t, func() {
rd := &ReportDump{}
So(rd.Empty(), ShouldBeTrue)
Convey(`Add`, func() {
rd.Add(
mkReport("proj-foo", "some.file", "TAG_THIRD", "another problem"),
mkReport("proj-foo", "", "TAG", "problem"),
mkReport("proj-foo", "", "TAG_OTHER", "problem"),
mkReport("other-proj", "", "TAG", "problem"),
)
So(rd.Empty(), ShouldBeFalse)
So(rd.data, ShouldHaveLength, 3)
So(rd.data[ReportID{"proj-foo", ""}], ShouldHaveLength, 2)
So(rd.data[ReportID{"proj-foo", ""}][0].Tag, ShouldResemble, "TAG")
So(rd.data[ReportID{"proj-foo", ""}][1].Tag, ShouldResemble, "TAG_OTHER")
So(rd.data[ReportID{"proj-foo", "some.file"}][0].Tag, ShouldResemble, "TAG_THIRD")
So(rd.data[ReportID{"other-proj", ""}], ShouldHaveLength, 1)
So(rd.data[ReportID{"other-proj", ""}][0].Tag, ShouldResemble, "TAG")
Convey(`Iterate`, func() {
reports := []*Report{}
rd.Iterate(func(rid ReportID, reps []*Report) bool {
for _, r := range reps {
So(rid, ShouldResemble, r.ReportID)
}
reports = append(reports, reps...)
return true
})
So(reports, ShouldHaveLength, 4)
So(reports[0].ReportID, ShouldResemble, ReportID{"other-proj", ""})
So(reports[1].ReportID, ShouldResemble, ReportID{"proj-foo", ""})
So(reports[2].ReportID, ShouldResemble, ReportID{"proj-foo", ""})
So(reports[3].ReportID, ShouldResemble, ReportID{"proj-foo", "some.file"})
})
Convey(`UpdateFrom`, func() {
So(rd.UpdateFrom(rd.Clone()), ShouldEqual, 4)
So(rd.data, ShouldHaveLength, 3)
So(rd.data[ReportID{"proj-foo", ""}], ShouldHaveLength, 4)
So(rd.data[ReportID{"proj-foo", ""}][0].Tag, ShouldResemble, "TAG")
So(rd.data[ReportID{"proj-foo", ""}][1].Tag, ShouldResemble, "TAG_OTHER")
So(rd.data[ReportID{"proj-foo", ""}][2].Tag, ShouldResemble, "TAG")
So(rd.data[ReportID{"proj-foo", ""}][3].Tag, ShouldResemble, "TAG_OTHER")
So(rd.data[ReportID{"proj-foo", "some.file"}][0].Tag, ShouldResemble, "TAG_THIRD")
So(rd.data[ReportID{"proj-foo", "some.file"}][1].Tag, ShouldResemble, "TAG_THIRD")
So(rd.data[ReportID{"other-proj", ""}], ShouldHaveLength, 2)
So(rd.data[ReportID{"other-proj", ""}][0].Tag, ShouldResemble, "TAG")
So(rd.data[ReportID{"other-proj", ""}][1].Tag, ShouldResemble, "TAG")
})
Convey(`Clone`, func() {
c := rd.Clone()
So(c.data, ShouldNotEqual, rd.data)
So(c.data, ShouldResemble, rd.data)
})
})
})
}
func TestReportCSV(t *testing.T) {
t.Parallel()
Convey(`Report CSV`, t, func() {
Convey(`Write`, func() {
rd := &ReportDump{}
rd.Add(
mkReport("proj-foo", "some.file", "TAG_THIRD", "another problem"),
mkReport("proj-foo", "", "TAG", "problem", "meta:data", "a:value"),
mkReport("proj-foo", "", "TAG_OTHER", "problem"),
mkReport("other-proj", "", "TAG", "problem"),
mkReport("a-third-prog", "", "TAG", "problem"),
)
buf := &bytes.Buffer{}
So(rd.WriteToCSV(buf), ShouldBeNil)
csvRead := csv.NewReader(buf)
csvRead.FieldsPerRecord = -1 // variable
lines, err := csvRead.ReadAll()
So(err, ShouldBeNil)
So(lines, ShouldResemble, [][]string{
csvHeader,
{"a-third-prog", "", "TAG", "problem", "false"},
{"other-proj", "", "TAG", "problem", "false"},
{"proj-foo", "", "TAG", "problem", "false", "a:value", "meta:data"},
{"proj-foo", "", "TAG_OTHER", "problem", "false"},
{"proj-foo", "some.file", "TAG_THIRD", "another problem", "false"},
})
})
Convey(`Read`, func() {
Convey(`OK`, func() {
buf := &bytes.Buffer{}
csvWrite := csv.NewWriter(buf)
csvWrite.WriteAll([][]string{
csvHeader,
{"a-third-prog", "", "TAG", "problem"},
{"other-proj", "", "TAG", "problem"},
{"proj-foo", "", "TAG", "problem", "a:value", "meta:data"},
{"proj-foo", "", "TAG_OTHER", "problem"},
{"proj-foo", "some.file", "TAG_THIRD", "another problem"},
})
csvWrite.Flush()
rd, err := NewReportDumpFromCSV(buf)
So(err, ShouldBeNil)
So(rd.data, ShouldResemble, map[ReportID][]*Report{
{"proj-foo", ""}: {
mkReport("proj-foo", "", "TAG", "problem", "meta:data", "a:value"),
mkReport("proj-foo", "", "TAG_OTHER", "problem"),
},
{"proj-foo", "some.file"}: {
mkReport("proj-foo", "some.file", "TAG_THIRD", "another problem"),
},
{"other-proj", ""}: {
mkReport("other-proj", "", "TAG", "problem"),
},
{"a-third-prog", ""}: {
mkReport("a-third-prog", "", "TAG", "problem"),
},
})
})
Convey(`Empty Header`, func() {
buf := &bytes.Buffer{}
buf.WriteString("\n")
_, err := NewReportDumpFromCSV(buf)
So(err, ShouldErrLike, "header was missing")
})
Convey(`Bad Schema`, func() {
buf := &bytes.Buffer{}
csvWrite := csv.NewWriter(buf)
header := append([]string(nil), csvHeader[:len(csvHeader)-1]...)
header = append(header, "{schema=v3}")
csvWrite.Write(header)
csvWrite.Flush()
_, err := NewReportDumpFromCSV(buf)
So(err, ShouldErrLike, "unexpected version: \"v3\", expected \"v2\"")
})
Convey(`Bad Header length`, func() {
buf := &bytes.Buffer{}
csvWrite := csv.NewWriter(buf)
csvWrite.WriteAll([][]string{
{"some", "stuff"},
})
csvWrite.Flush()
_, err := NewReportDumpFromCSV(buf)
So(err, ShouldErrLike, "unexpected header:")
})
Convey(`Bad Header content`, func() {
buf := &bytes.Buffer{}
csvWrite := csv.NewWriter(buf)
csvWrite.WriteAll([][]string{
{"1", "2", "3", "4", "5", "6"},
})
csvWrite.Flush()
_, err := NewReportDumpFromCSV(buf)
So(err, ShouldErrLike, "unexpected header:")
})
Convey(`Bad Row`, func() {
buf := &bytes.Buffer{}
csvWrite := csv.NewWriter(buf)
csvWrite.WriteAll([][]string{
csvHeader,
{"wat"},
})
csvWrite.Flush()
_, err := NewReportDumpFromCSV(buf)
So(err, ShouldErrLike, "reading row 2")
})
})
})
}