diff --git a/Makefile b/Makefile index 6b408d1488a..4655d807864 100644 --- a/Makefile +++ b/Makefile @@ -139,3 +139,4 @@ clear-swarm-data: test: go test ./pkg/query-service/app/metrics/... go test ./pkg/query-service/app/... + go test ./pkg/query-service/converter/... \ No newline at end of file diff --git a/pkg/query-service/converter/bool.go b/pkg/query-service/converter/bool.go new file mode 100644 index 00000000000..2183c3b2a4a --- /dev/null +++ b/pkg/query-service/converter/bool.go @@ -0,0 +1,16 @@ +package converter + +// boolConverter is a Converter implementation for bool +type boolConverter struct{} + +func NewBoolConverter() Converter { + return &boolConverter{} +} + +func (c *boolConverter) Convert(v Value, to Unit) Value { + // There is no conversion to be done for bool + return Value{ + F: v.F, + U: to, + } +} diff --git a/pkg/query-service/converter/converter.go b/pkg/query-service/converter/converter.go new file mode 100644 index 00000000000..82f87b88055 --- /dev/null +++ b/pkg/query-service/converter/converter.go @@ -0,0 +1,53 @@ +package converter + +// Unit represents a unit of measurement +type Unit string + +// Value represents a value with a unit of measurement +type Value struct { + F float64 + U Unit +} + +// Converter converts values from one unit to another +type Converter interface { + Convert(v Value, to Unit) Value +} + +// noneConverter is a converter that does not convert +type noneConverter struct{} + +func (c *noneConverter) Convert(v Value, to Unit) Value { + return v +} + +// Converters +var ( + DurationConverter = NewDurationConverter() + DataConverter = NewDataConverter() + DataRateConverter = NewDataRateConverter() + PercentConverter = NewPercentConverter() + BoolConverter = NewBoolConverter() + ThroughputConverter = NewThroughputConverter() + NoneConverter = &noneConverter{} +) + +// FromUnit returns a converter for the given unit +func FromUnit(u Unit) Converter { + switch u { + case "ns", "us", "ms", "s", "m", "h", "d": + return DurationConverter + case "bytes", "decbytes", "bits", "decbits", "kbytes", "decKbytes", "mbytes", "decMbytes", "gbytes", "decGbytes", "tbytes", "decTbytes", "pbytes", "decPbytes": + return DataConverter + case "binBps", "Bps", "binbps", "bps", "KiBs", "Kibits", "KBs", "Kbits", "MiBs", "Mibits", "MBs", "Mbits", "GiBs", "Gibits", "GBs", "Gbits", "TiBs", "Tibits", "TBs", "Tbits", "PiBs", "Pibits", "PBs", "Pbits": + return DataRateConverter + case "percent", "percentunit": + return PercentConverter + case "bool", "bool_yes_no", "bool_true_false", "bool_1_0": + return BoolConverter + case "cps", "ops", "reqps", "rps", "wps", "iops", "cpm", "opm", "rpm", "wpm": + return ThroughputConverter + default: + return NoneConverter + } +} diff --git a/pkg/query-service/converter/data.go b/pkg/query-service/converter/data.go new file mode 100644 index 00000000000..f7252a2bc38 --- /dev/null +++ b/pkg/query-service/converter/data.go @@ -0,0 +1,97 @@ +package converter + +const ( + // base 10 (SI prefixes) + Bit float64 = 1e0 + Kilobit = Bit * 1e3 + Megabit = Bit * 1e6 + Gigabit = Bit * 1e9 + Terabit = Bit * 1e12 + Petabit = Bit * 1e15 + Exabit = Bit * 1e18 + Zettabit = Bit * 1e21 + Yottabit = Bit * 1e24 + Ronnabit = Bit * 1e27 + Quettabit = Bit * 1e30 + + Byte = Bit * 8 + Kilobyte = Byte * 1e3 + Megabyte = Byte * 1e6 + Gigabyte = Byte * 1e9 + Terabyte = Byte * 1e12 + Petabyte = Byte * 1e15 + Exabyte = Byte * 1e18 + Zettabyte = Byte * 1e21 + Yottabyte = Byte * 1e24 + Ronnabyte = Byte * 1e27 + Quettabyte = Byte * 1e30 + + // base 2 (IEC prefixes) + Kibibit = Bit * 1024 + Mebibit = Kibibit * 1024 + Gibibit = Mebibit * 1024 + Tebibit = Gibibit * 1024 + Pebibit = Tebibit * 1024 + Exbibit = Pebibit * 1024 + Zebibit = Exbibit * 1024 + Yobibit = Zebibit * 1024 + + Kibibyte = Byte * 1024 + Mebibyte = Kibibyte * 1024 + Gibibyte = Mebibyte * 1024 + Tebibyte = Gibibyte * 1024 + Pebibyte = Tebibyte * 1024 + Exbibyte = Pebibyte * 1024 + Zebibyte = Exbibyte * 1024 + Yobibyte = Zebibyte * 1024 +) + +// dataConverter is a Converter for data units. +type dataConverter struct { +} + +func NewDataConverter() Converter { + return &dataConverter{} +} + +func FromDataUnit(u Unit) float64 { + switch u { + case "bytes": // base 2 + return Byte + case "decbytes": // base 10 + return Byte + case "bits": // base 2 + return Bit + case "decbits": // base 10 + return Bit + case "kbytes": // base 2 + return Kibibyte + case "deckbytes": // base 10 + return Kilobyte + case "mbytes": // base 2 + return Mebibyte + case "decmbytes": // base 10 + return Megabyte + case "gbytes": // base 2 + return Gibibyte + case "decgbytes": // base 10 + return Gigabyte + case "tbytes": // base 2 + return Tebibyte + case "dectbytes": // base 10 + return Terabyte + case "pbytes": // base 2 + return Pebibyte + case "decpbytes": // base 10 + return Petabyte + default: + return 1 + } +} + +func (c *dataConverter) Convert(v Value, to Unit) Value { + return Value{ + F: v.F * FromDataUnit(v.U) / FromDataUnit(to), + U: to, + } +} diff --git a/pkg/query-service/converter/data_rate.go b/pkg/query-service/converter/data_rate.go new file mode 100644 index 00000000000..39513417332 --- /dev/null +++ b/pkg/query-service/converter/data_rate.go @@ -0,0 +1,114 @@ +package converter + +const ( + // base 10 (SI prefixes) + BitPerSecond float64 = 1e0 + KilobitPerSecond = BitPerSecond * 1e3 + MegabitPerSecond = BitPerSecond * 1e6 + GigabitPerSecond = BitPerSecond * 1e9 + TerabitPerSecond = BitPerSecond * 1e12 + PetabitPerSecond = BitPerSecond * 1e15 + ExabitPerSecond = BitPerSecond * 1e18 + ZettabitPerSecond = BitPerSecond * 1e21 + YottabitPerSecond = BitPerSecond * 1e24 + + BytePerSecond = BitPerSecond * 8 + KilobytePerSecond = BytePerSecond * 1e3 + MegabytePerSecond = BytePerSecond * 1e6 + GigabytePerSecond = BytePerSecond * 1e9 + TerabytePerSecond = BytePerSecond * 1e12 + PetabytePerSecond = BytePerSecond * 1e15 + ExabytePerSecond = BytePerSecond * 1e18 + ZettabytePerSecond = BytePerSecond * 1e21 + YottabytePerSecond = BytePerSecond * 1e24 + + // base 2 (IEC prefixes) + KibibitPerSecond = BitPerSecond * 1024 + MebibitPerSecond = KibibitPerSecond * 1024 + GibibitPerSecond = MebibitPerSecond * 1024 + TebibitPerSecond = GibibitPerSecond * 1024 + PebibitPerSecond = TebibitPerSecond * 1024 + ExbibitPerSecond = PebibitPerSecond * 1024 + ZebibitPerSecond = ExbibitPerSecond * 1024 + YobibitPerSecond = ZebibitPerSecond * 1024 + + KibibytePerSecond = BytePerSecond * 1024 + MebibytePerSecond = KibibytePerSecond * 1024 + GibibytePerSecond = MebibytePerSecond * 1024 + TebibytePerSecond = GibibytePerSecond * 1024 + PebibytePerSecond = TebibytePerSecond * 1024 + ExbibytePerSecond = PebibytePerSecond * 1024 + ZebibytePerSecond = ExbibytePerSecond * 1024 + YobibytePerSecond = ZebibytePerSecond * 1024 +) + +// dataRateConverter is a Converter implementation for data rates +type dataRateConverter struct { +} + +func NewDataRateConverter() Converter { + return &dataRateConverter{} +} + +func FromDataRateUnit(u Unit) float64 { + // See https://github.com/SigNoz/signoz/blob/5a81f5f90b34845f5b4b3bdd46acf29d04bf3987/frontend/src/container/NewWidget/RightContainer/dataFormatCategories.ts#L62-L85 + switch u { + case "binBps": // bytes/sec(IEC) + return BytePerSecond + case "Bps": // bytes/sec(SI) + return BytePerSecond + case "binbps": // bits/sec(IEC) + return BitPerSecond + case "bps": // bits/sec(SI) + return BitPerSecond + case "KiBs": // kibibytes/sec + return KibibytePerSecond + case "Kibits": // kibibits/sec + return KibibitPerSecond + case "KBs": // kilobytes/sec + return KilobytePerSecond + case "Kbits": // kilobits/sec + return KilobitPerSecond + case "MiBs": // mebibytes/sec + return MebibytePerSecond + case "Mibits": // mebibits/sec + return MebibitPerSecond + case "MBs": // megabytes/sec + return MegabytePerSecond + case "Mbits": // megabits/sec + return MegabitPerSecond + case "GiBs": // gibibytes/sec + return GibibytePerSecond + case "Gibits": // gibibits/sec + return GibibitPerSecond + case "GBs": // gigabytes/sec + return GigabytePerSecond + case "Gbits": // gigabits/sec + return GigabitPerSecond + case "TiBs": // tebibytes/sec + return TebibytePerSecond + case "Tibits": // tebibits/sec + return TebibitPerSecond + case "TBs": // terabytes/sec + return TerabytePerSecond + case "Tbits": // terabits/sec + return TerabitPerSecond + case "PiBs": // pebibytes/sec + return PebibytePerSecond + case "Pibits": // pebibits/sec + return PebibitPerSecond + case "PBs": // petabytes/sec + return PetabytePerSecond + case "Pbits": // petabits/sec + return PetabitPerSecond + default: + return 1 + } +} + +func (c *dataRateConverter) Convert(v Value, to Unit) Value { + return Value{ + F: v.F * FromDataRateUnit(v.U) / FromDataRateUnit(to), + U: to, + } +} diff --git a/pkg/query-service/converter/data_rate_test.go b/pkg/query-service/converter/data_rate_test.go new file mode 100644 index 00000000000..dda0f7886e2 --- /dev/null +++ b/pkg/query-service/converter/data_rate_test.go @@ -0,0 +1,67 @@ +package converter + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDataRate(t *testing.T) { + dataRateConverter := NewDataRateConverter() + // names and ids for data rate units + // { name: 'bytes/sec(IEC)', id: 'binBps' }, + // { name: 'bytes/sec(SI)', id: 'Bps' }, + // { name: 'bits/sec(IEC)', id: 'binbps' }, + // { name: 'bits/sec(SI)', id: 'bps' }, + // { name: 'kibibytes/sec', id: 'KiBs' }, + // { name: 'kibibits/sec', id: 'Kibits' }, + // { name: 'kilobytes/sec', id: 'KBs' }, + // { name: 'kilobits/sec', id: 'Kbits' }, + // { name: 'mebibytes/sec', id: 'MiBs' }, + // { name: 'mebibits/sec', id: 'Mibits' }, + // { name: 'megabytes/sec', id: 'MBs' }, + // { name: 'megabits/sec', id: 'Mbits' }, + // { name: 'gibibytes/sec', id: 'GiBs' }, + // { name: 'gibibits/sec', id: 'Gibits' }, + // { name: 'gigabytes/sec', id: 'GBs' }, + // { name: 'gigabits/sec', id: 'Gbits' }, + // { name: 'tebibytes/sec', id: 'TiBs' }, + // { name: 'tebibits/sec', id: 'Tibits' }, + // { name: 'terabytes/sec', id: 'TBs' }, + // { name: 'terabits/sec', id: 'Tbits' }, + // { name: 'pebibytes/sec', id: 'PiBs' }, + // { name: 'pebibits/sec', id: 'Pibits' }, + // { name: 'petabytes/sec', id: 'PBs' }, + // { name: 'petabits/sec', id: 'Pbits' }, + + // 8 bits = 1 byte + assert.Equal(t, Value{F: 1, U: "binBps"}, dataRateConverter.Convert(Value{F: 8, U: "binbps"}, "binBps")) + // 1024 bytes = 1 kbytes + assert.Equal(t, Value{F: 1, U: "KiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "binBps"}, "KiBs")) + // 1 byte = 8 bits + assert.Equal(t, Value{F: 8, U: "binbps"}, dataRateConverter.Convert(Value{F: 1, U: "binBps"}, "binbps")) + // 1 mbytes = 1024 kbytes + assert.Equal(t, Value{F: 1, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "KiBs"}, "MiBs")) + // 1 kbytes = 1024 bytes + assert.Equal(t, Value{F: 1024, U: "binBps"}, dataRateConverter.Convert(Value{F: 1, U: "KiBs"}, "binBps")) + // 1024 kbytes = 1 mbytes + assert.Equal(t, Value{F: 1, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "KiBs"}, "MiBs")) + // 1 mbytes = 1024 * 1024 bytes + assert.Equal(t, Value{F: 1024 * 1024, U: "binBps"}, dataRateConverter.Convert(Value{F: 1, U: "MiBs"}, "binBps")) + // 1024 mbytes = 1 gbytes + assert.Equal(t, Value{F: 1, U: "GiBs"}, dataRateConverter.Convert(Value{F: 1024, U: "MiBs"}, "GiBs")) + // 2048 mbytes = 2 gbytes + assert.Equal(t, Value{F: 2, U: "GiBs"}, dataRateConverter.Convert(Value{F: 2048, U: "MiBs"}, "GiBs")) + // 1 gbytes = 1024 mbytes + assert.Equal(t, Value{F: 1024, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1, U: "GiBs"}, "MiBs")) + // 1 gbytes = 1024 * 1024 kbytes + assert.Equal(t, Value{F: 1024 * 1024, U: "KiBs"}, dataRateConverter.Convert(Value{F: 1, U: "GiBs"}, "KiBs")) + // 1 gbytes = 1024 * 1024 * 1024 bytes + assert.Equal(t, Value{F: 1024 * 1024 * 1024, U: "binBps"}, dataRateConverter.Convert(Value{F: 1, U: "GiBs"}, "binBps")) + // 1024 * 1024 bytes = 1 mbytes + assert.Equal(t, Value{F: 1, U: "MiBs"}, dataRateConverter.Convert(Value{F: 1024 * 1024, U: "binBps"}, "MiBs")) + // 1024 * 1024 kbytes = 1 gbytes + assert.Equal(t, Value{F: 1, U: "GiBs"}, dataRateConverter.Convert(Value{F: 1024 * 1024, U: "KiBs"}, "GiBs")) + // 1024 * 1024 * 1024 bytes = 1 gbytes + assert.Equal(t, Value{F: 1, U: "GiBs"}, dataRateConverter.Convert(Value{F: 1024 * 1024 * 1024, U: "binBps"}, "GiBs")) +} diff --git a/pkg/query-service/converter/data_test.go b/pkg/query-service/converter/data_test.go new file mode 100644 index 00000000000..b484b8172df --- /dev/null +++ b/pkg/query-service/converter/data_test.go @@ -0,0 +1,47 @@ +package converter + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestData(t *testing.T) { + dataConverter := NewDataConverter() + // 8 bits = 1 byte + assert.Equal(t, Value{F: 1, U: "bytes"}, dataConverter.Convert(Value{F: 8, U: "bits"}, "bytes")) + // 1024 bytes = 1 kbytes + assert.Equal(t, Value{F: 1, U: "kbytes"}, dataConverter.Convert(Value{F: 1024, U: "bytes"}, "kbytes")) + // 1 byte = 8 bits + assert.Equal(t, Value{F: 8, U: "bits"}, dataConverter.Convert(Value{F: 1, U: "bytes"}, "bits")) + // 1 mbytes = 1024 kbytes + assert.Equal(t, Value{F: 1024, U: "kbytes"}, dataConverter.Convert(Value{F: 1, U: "mbytes"}, "kbytes")) + // 1 kbytes = 1024 bytes + assert.Equal(t, Value{F: 1024, U: "bytes"}, dataConverter.Convert(Value{F: 1, U: "kbytes"}, "bytes")) + // 1024 kbytes = 1 mbytes + assert.Equal(t, Value{F: 1, U: "mbytes"}, dataConverter.Convert(Value{F: 1024, U: "kbytes"}, "mbytes")) + // 1 mbytes = 1024 * 1024 bytes + assert.Equal(t, Value{F: 1024 * 1024, U: "bytes"}, dataConverter.Convert(Value{F: 1, U: "mbytes"}, "bytes")) + // 1024 mbytes = 1 gbytes + assert.Equal(t, Value{F: 1, U: "gbytes"}, dataConverter.Convert(Value{F: 1024, U: "mbytes"}, "gbytes")) + // 1 gbytes = 1024 mbytes + assert.Equal(t, Value{F: 1024, U: "mbytes"}, dataConverter.Convert(Value{F: 1, U: "gbytes"}, "mbytes")) + // 1 gbytes = 1024 * 1024 kbytes + assert.Equal(t, Value{F: 1024 * 1024, U: "kbytes"}, dataConverter.Convert(Value{F: 1, U: "gbytes"}, "kbytes")) + // 1 gbytes = 1024 * 1024 * 1024 bytes + assert.Equal(t, Value{F: 1024 * 1024 * 1024, U: "bytes"}, dataConverter.Convert(Value{F: 1, U: "gbytes"}, "bytes")) + // 1024 gbytes = 1 tbytes + assert.Equal(t, Value{F: 1, U: "tbytes"}, dataConverter.Convert(Value{F: 1024, U: "gbytes"}, "tbytes")) + // 1 tbytes = 1024 gbytes + assert.Equal(t, Value{F: 1024, U: "gbytes"}, dataConverter.Convert(Value{F: 1, U: "tbytes"}, "gbytes")) + // 1 tbytes = 1024 * 1024 mbytes + assert.Equal(t, Value{F: 1024 * 1024, U: "mbytes"}, dataConverter.Convert(Value{F: 1, U: "tbytes"}, "mbytes")) + // 1 tbytes = 1024 * 1024 * 1024 kbytes + assert.Equal(t, Value{F: 1024 * 1024 * 1024, U: "kbytes"}, dataConverter.Convert(Value{F: 1, U: "tbytes"}, "kbytes")) + // 1 tbytes = 1024 * 1024 * 1024 * 1024 bytes + assert.Equal(t, Value{F: 1024 * 1024 * 1024 * 1024, U: "bytes"}, dataConverter.Convert(Value{F: 1, U: "tbytes"}, "bytes")) + // 1024 tbytes = 1 pbytes + assert.Equal(t, Value{F: 1, U: "pbytes"}, dataConverter.Convert(Value{F: 1024, U: "tbytes"}, "pbytes")) + // 1 pbytes = 1024 tbytes + assert.Equal(t, Value{F: 1024, U: "tbytes"}, dataConverter.Convert(Value{F: 1, U: "pbytes"}, "tbytes")) +} diff --git a/pkg/query-service/converter/percent_converter.go b/pkg/query-service/converter/percent_converter.go new file mode 100644 index 00000000000..6597da93aae --- /dev/null +++ b/pkg/query-service/converter/percent_converter.go @@ -0,0 +1,26 @@ +package converter + +// percentConverter is a converter for percent unit +type percentConverter struct{} + +func NewPercentConverter() Converter { + return &percentConverter{} +} + +func FromPercentUnit(u Unit) float64 { + switch u { + case "percent": + return 1 + case "percentunit": + return 100 + default: + return 1 + } +} + +func (c *percentConverter) Convert(v Value, to Unit) Value { + return Value{ + F: v.F * FromPercentUnit(v.U) / FromPercentUnit(to), + U: to, + } +} diff --git a/pkg/query-service/converter/percent_converter_test.go b/pkg/query-service/converter/percent_converter_test.go new file mode 100644 index 00000000000..5001ef19645 --- /dev/null +++ b/pkg/query-service/converter/percent_converter_test.go @@ -0,0 +1,16 @@ +package converter + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPercentConverter(t *testing.T) { + percentConverter := NewPercentConverter() + + assert.Equal(t, Value{F: 1, U: "percent"}, percentConverter.Convert(Value{F: 1, U: "percent"}, "percent")) + assert.Equal(t, Value{F: 100, U: "percent"}, percentConverter.Convert(Value{F: 1, U: "percentunit"}, "percent")) + assert.Equal(t, Value{F: 1, U: "percentunit"}, percentConverter.Convert(Value{F: 100, U: "percent"}, "percentunit")) + assert.Equal(t, Value{F: 0.01, U: "percentunit"}, percentConverter.Convert(Value{F: 1, U: "percent"}, "percentunit")) +} diff --git a/pkg/query-service/converter/throughput.go b/pkg/query-service/converter/throughput.go new file mode 100644 index 00000000000..7c38257b811 --- /dev/null +++ b/pkg/query-service/converter/throughput.go @@ -0,0 +1,17 @@ +package converter + +// throughputConverter is an implementation of Converter that converts throughput +type throughputConverter struct { +} + +func NewThroughputConverter() Converter { + return &throughputConverter{} +} + +func (c *throughputConverter) Convert(v Value, to Unit) Value { + // There is no conversion to be done for throughput + return Value{ + F: v.F, + U: to, + } +} diff --git a/pkg/query-service/converter/time.go b/pkg/query-service/converter/time.go new file mode 100644 index 00000000000..c4f1f03c8a8 --- /dev/null +++ b/pkg/query-service/converter/time.go @@ -0,0 +1,58 @@ +package converter + +type Duration float64 + +const ( + Nanosecond = Second * 1e-9 + Microsecond = Second * 1e-6 + Millisecond = Second * 1e-3 + Centisecond = Second * 1e-2 + Decisecond = Second * 1e-1 + Second Duration = 1e0 + Minute = Second * 60 + Hour = Minute * 60 + Day = Hour * 24 + Week = Day * 7 +) + +// durationConverter is an implementation of Converter for durations. +type durationConverter struct { +} + +func NewDurationConverter() Converter { + return &durationConverter{} +} + +func FromTimeUnit(u Unit) Duration { + switch u { + case "ns": + return Nanosecond + case "us": + return Microsecond + case "ms": + return Millisecond + case "cs": + return Centisecond + case "ds": + return Decisecond + case "s": + return Second + case "m": + return Minute + case "h": + return Hour + case "d": + return Day + case "w": + return Week + default: + return Second + } +} + +func (c *durationConverter) Convert(v Value, to Unit) Value { + return Value{ + F: v.F * float64(FromTimeUnit(v.U)) / float64(FromTimeUnit(to)), + U: to, + } +} diff --git a/pkg/query-service/converter/time_test.go b/pkg/query-service/converter/time_test.go new file mode 100644 index 00000000000..910b82e16df --- /dev/null +++ b/pkg/query-service/converter/time_test.go @@ -0,0 +1,55 @@ +package converter + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDurationConvert(t *testing.T) { + timeConverter := NewDurationConverter() + // 1000 ms = 1 s + assert.Equal(t, Value{F: 1, U: "s"}, timeConverter.Convert(Value{F: 1000, U: "ms"}, "s")) + // 1000000 us = 1 s + assert.Equal(t, Value{F: 1, U: "s"}, timeConverter.Convert(Value{F: 1000000, U: "us"}, "s")) + // 100000 ms = 100 s + assert.Equal(t, Value{F: 100, U: "s"}, timeConverter.Convert(Value{F: 100000, U: "ms"}, "s")) + // 1 s = 1000 ms + assert.Equal(t, Value{F: 1000, U: "ms"}, timeConverter.Convert(Value{F: 1, U: "s"}, "ms")) + // 60 s = 1 m + assert.Equal(t, Value{F: 1, U: "m"}, timeConverter.Convert(Value{F: 60, U: "s"}, "m")) + // 604800000000000 ns = 1 w + assert.Equal(t, Value{F: 1, U: "w"}, timeConverter.Convert(Value{F: 604800000000000, U: "ns"}, "w")) + // 1 m = 60 s + assert.Equal(t, Value{F: 60, U: "s"}, timeConverter.Convert(Value{F: 1, U: "m"}, "s")) + // 60 m = 1 h + assert.Equal(t, Value{F: 1, U: "h"}, timeConverter.Convert(Value{F: 60, U: "m"}, "h")) + // 168 h = 1 w + assert.Equal(t, Value{F: 1, U: "w"}, timeConverter.Convert(Value{F: 168, U: "h"}, "w")) + // 1 h = 60 m + assert.Equal(t, Value{F: 60, U: "m"}, timeConverter.Convert(Value{F: 1, U: "h"}, "m")) + // 24 h = 1 d + assert.Equal(t, Value{F: 1, U: "d"}, timeConverter.Convert(Value{F: 24, U: "h"}, "d")) + // 10080 m = 1 w + assert.Equal(t, Value{F: 1, U: "w"}, timeConverter.Convert(Value{F: 10080, U: "m"}, "w")) + // 1 d = 24 h + assert.Equal(t, Value{F: 24, U: "h"}, timeConverter.Convert(Value{F: 1, U: "d"}, "h")) + // 7 d = 1 w + assert.Equal(t, Value{F: 1, U: "w"}, timeConverter.Convert(Value{F: 7, U: "d"}, "w")) + // 1 w = 7 d + assert.Equal(t, Value{F: 7, U: "d"}, timeConverter.Convert(Value{F: 1, U: "w"}, "d")) + // 1 w = 168 h + assert.Equal(t, Value{F: 168, U: "h"}, timeConverter.Convert(Value{F: 1, U: "w"}, "h")) + // 1 w = 10080 m + assert.Equal(t, Value{F: 10080, U: "m"}, timeConverter.Convert(Value{F: 1, U: "w"}, "m")) + // 604800 s = 1 w + assert.Equal(t, Value{F: 1, U: "w"}, timeConverter.Convert(Value{F: 604800, U: "s"}, "w")) + // 1 w = 604800 s + assert.Equal(t, Value{F: 604800, U: "s"}, timeConverter.Convert(Value{F: 1, U: "w"}, "s")) + // 1 w = 604800000000000 ns + assert.Equal(t, Value{F: 604800000000000, U: "ns"}, timeConverter.Convert(Value{F: 1, U: "w"}, "ns")) + // 1000 us = 1 ms + assert.Equal(t, Value{F: 1, U: "ms"}, timeConverter.Convert(Value{F: 1000, U: "us"}, "ms")) + // 1000000000 ns = 1 s + assert.Equal(t, Value{F: 1, U: "s"}, timeConverter.Convert(Value{F: 1000000000, U: "ns"}, "s")) +}