Update metering UT.

Signed-off-by: Rao Yunkun <yunkunrao@yunify.com>
This commit is contained in:
Rao Yunkun
2021-03-31 21:18:56 +08:00
parent 76ffaa8794
commit 836b279fee
4 changed files with 617 additions and 11 deletions

View File

@@ -274,7 +274,7 @@ func TestParseRequestParams(t *testing.T) {
{
params: reqParams{
namespaceName: "default",
openpitrixs: "op1|op2",
openpitrixs: "op1|op2",
},
lvl: monitoring.LevelOpenpitrix,
expectedErr: true,
@@ -287,10 +287,8 @@ func TestParseRequestParams(t *testing.T) {
expectedErr: true,
},
{
params: reqParams{
},
lvl: monitoring.LevelOpenpitrix,
params: reqParams{},
lvl: monitoring.LevelOpenpitrix,
expectedErr: true,
},
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"math/big"
"os"
"path/filepath"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/klog"
@@ -18,7 +19,8 @@ const (
METER_RESOURCE_TYPE_NET_EGRESS
METER_RESOURCE_TYPE_PVC
meteringConfig = "/etc/kubesphere/metering/ks-metering.yaml"
meteringConfigDir = "/etc/kubesphere/metering/"
meteringConfigName = "ks-metering.yaml"
meteringDefaultPrecision = 10
meteringCorePrecision = 3
@@ -103,11 +105,21 @@ func (mc MeterConfig) GetPriceInfo() PriceInfo {
func LoadYaml() (*MeterConfig, error) {
var meterConfig MeterConfig
var mf *os.File
var err error
mf, err := os.Open(meteringConfig)
if err != nil {
klog.Error(err)
return nil, err
if _, err := os.Stat(meteringConfigName); os.IsNotExist(err) {
mf, err = os.Open(filepath.Join(meteringConfigDir, meteringConfigName))
if err != nil {
klog.Error(err)
return nil, err
}
} else {
mf, err = os.Open(meteringConfigName)
if err != nil {
klog.Error(err)
return nil, err
}
}
if err = yaml.NewYAMLOrJSONDecoder(mf, 1024).Decode(&meterConfig); err != nil {
@@ -170,7 +182,7 @@ func getAvgPointValue(points []monitoring.Point) string {
length := new(big.Float).SetFloat64(float64(len(points)))
return fmt.Sprintf("%.3f", sum.Quo(sum, length))
return fmt.Sprintf(generateFloatFormat(meteringDefaultPrecision), sum.Quo(sum, length))
}
func getCurrencyUnit() string {

View File

@@ -0,0 +1,403 @@
package monitoring
import (
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/google/go-cmp/cmp"
"gopkg.in/yaml.v2"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
func TestGetMaxPointValue(t *testing.T) {
tests := []struct {
actualPoints []monitoring.Point
expectedValue string
}{
{
actualPoints: []monitoring.Point{
{1.0, 2.0},
{3.0, 4.0},
},
expectedValue: "4.0000000000",
},
{
actualPoints: []monitoring.Point{
{2, 1},
{4, 3.1},
},
expectedValue: "3.1000000000",
},
{
actualPoints: []monitoring.Point{
{5, 100},
{6, 100000.001},
},
expectedValue: "100000.0010000000",
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
max := getMaxPointValue(tt.actualPoints)
if max != tt.expectedValue {
t.Fatal("max point value caculation is wrong.")
}
})
}
}
func TestGetMinPointValue(t *testing.T) {
tests := []struct {
actualPoints []monitoring.Point
expectedValue string
}{
{
actualPoints: []monitoring.Point{
{1.0, 2.0},
{3.0, 4.0},
},
expectedValue: "2.0000000000",
},
{
actualPoints: []monitoring.Point{
{2, 1},
{4, 3.1},
},
expectedValue: "1.0000000000",
},
{
actualPoints: []monitoring.Point{
{5, 100},
{6, 100000.001},
},
expectedValue: "100.0000000000",
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
max := getMinPointValue(tt.actualPoints)
if max != tt.expectedValue {
t.Fatal("min point value caculation is wrong.")
}
})
}
}
func TestGetSumPointValue(t *testing.T) {
tests := []struct {
actualPoints []monitoring.Point
expectedValue string
}{
{
actualPoints: []monitoring.Point{
{1.0, 2.0},
{3.0, 4.0},
},
expectedValue: "6.0000000000",
},
{
actualPoints: []monitoring.Point{
{2, 1},
{4, 3.1},
},
expectedValue: "4.1000000000",
},
{
actualPoints: []monitoring.Point{
{5, 100},
{6, 100000.001},
},
expectedValue: "100100.0010000000",
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
max := getSumPointValue(tt.actualPoints)
if max != tt.expectedValue {
t.Fatal("sum point value caculation is wrong.")
}
})
}
}
func TestGetAvgPointValue(t *testing.T) {
tests := []struct {
actualPoints []monitoring.Point
expectedValue string
}{
{
actualPoints: []monitoring.Point{
{1.0, 2.0},
{3.0, 4.0},
},
expectedValue: "3.0000000000",
},
{
actualPoints: []monitoring.Point{
{2, 1},
{4, 3.1},
},
expectedValue: "2.0500000000",
},
{
actualPoints: []monitoring.Point{
{5, 100},
{6, 100000.001},
},
expectedValue: "50050.0005000000",
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
max := getAvgPointValue(tt.actualPoints)
if max != tt.expectedValue {
t.Fatal("avg point value caculattion is wrong.")
}
})
}
}
func saveTestConfig(t *testing.T, conf *MeterConfig) {
content, err := yaml.Marshal(conf)
if err != nil {
t.Fatalf("error marshal config. %v", err)
}
err = ioutil.WriteFile(meteringConfigName, content, 0640)
if err != nil {
t.Fatalf("error write configuration file, %v", err)
}
}
func cleanTestConfig(t *testing.T) {
if _, err := os.Stat(meteringConfigName); os.IsNotExist(err) {
t.Log("file not exists, skipping")
return
}
err := os.Remove(meteringConfigName)
if err != nil {
t.Fatalf("remove %s file failed", meteringConfigName)
}
}
func TestGetCurrencyUnit(t *testing.T) {
if getCurrencyUnit() != "" {
t.Fatal("currency unit should be empty")
}
saveTestConfig(t, &MeterConfig{
Billing: Billing{
PriceInfo: PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
},
},
})
defer cleanTestConfig(t)
if getCurrencyUnit() != "CNY" {
t.Fatal("failed to get currency unit from config")
}
}
func TestGenerateFloatFormat(t *testing.T) {
format := generateFloatFormat(10)
if format != "%.10f" {
t.Fatalf("get currency float format failed, %s", format)
}
}
func TestGetResourceUnit(t *testing.T) {
tests := []struct {
meterName string
expectedValue string
}{
{
meterName: "no-exist",
expectedValue: "",
},
{
meterName: "meter_cluster_cpu_usage",
expectedValue: "cores",
},
}
for _, tt := range tests {
if getResourceUnit(tt.meterName) != tt.expectedValue {
t.Fatal("get resource unit failed")
}
}
}
func TestSquashPoints(t *testing.T) {
tests := []struct {
input []monitoring.Point
factor int
expected []monitoring.Point
}{
{
input: []monitoring.Point{
{1, 1},
{2, 2},
{3, 3},
{4, 4},
{5, 5},
{6, 6},
{7, 7},
{8, 8},
},
factor: 1,
expected: []monitoring.Point{
{1, 1},
{2, 2},
{3, 3},
{4, 4},
{5, 5},
{6, 6},
{7, 7},
{8, 8},
},
},
{
input: []monitoring.Point{
{1, 1},
{2, 2},
{3, 3},
{4, 4},
{5, 5},
{6, 6},
{7, 7},
{8, 8},
},
factor: 2,
expected: []monitoring.Point{
{2, 3},
{4, 7},
{6, 11},
{8, 15},
},
},
}
for _, tt := range tests {
got := squashPoints(tt.input, tt.factor)
if diff := cmp.Diff(got, tt.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", tt.expected, diff)
}
}
}
func TestGetFeeWithMeterName(t *testing.T) {
saveTestConfig(t, &MeterConfig{
Billing: Billing{
PriceInfo: PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
},
},
})
defer cleanTestConfig(t)
tests := []struct {
metric monitoring.Metric
scalingMap map[string]float64
expected monitoring.MetricData
}{
{
metric: monitoring.Metric{
MetricName: "test",
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeMatrix,
MetricValues: []monitoring.MetricValue{
{
Metadata: map[string]string{},
Series: []monitoring.Point{
{1, 1},
{2, 2},
},
},
},
},
},
scalingMap: map[string]float64{
"test": 1,
},
expected: monitoring.MetricData{
MetricType: monitoring.MetricTypeMatrix,
MetricValues: []monitoring.MetricValue{
{
Metadata: map[string]string{},
Series: []monitoring.Point{
{1, 1},
{2, 2},
},
MinValue: "1.0000000000",
MaxValue: "2.0000000000",
AvgValue: "1.5000000000",
SumValue: "3.0000000000",
CurrencyUnit: "CNY",
},
},
},
},
{
metric: monitoring.Metric{
MetricName: "test",
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Metadata: map[string]string{},
Sample: &monitoring.Point{1, 2},
},
},
},
},
scalingMap: nil,
expected: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Metadata: map[string]string{},
Sample: &monitoring.Point{1, 2},
MinValue: "2.0000000000",
MaxValue: "2.0000000000",
AvgValue: "2.0000000000",
SumValue: "2.0000000000",
CurrencyUnit: "CNY",
},
},
},
},
}
for _, test := range tests {
got := updateMetricStatData(test.metric, test.scalingMap)
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
return
}
}
}

View File

@@ -0,0 +1,193 @@
package tenant
import (
"fmt"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"kubesphere.io/kubesphere/pkg/models/metering"
monitoringmodel "kubesphere.io/kubesphere/pkg/models/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
func TestIsRangeQuery(t *testing.T) {
tests := []struct {
options QueryOptions
expectedValue bool
}{
{
options: QueryOptions{},
expectedValue: true,
},
{
options: QueryOptions{Time: time.Now()},
expectedValue: false,
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
if tt.options.isRangeQuery() != tt.expectedValue {
t.Fatal("error isRangeQuery")
}
})
}
}
func TestShouldSort(t *testing.T) {
tests := []struct {
options QueryOptions
expectedValue bool
}{
{
options: QueryOptions{
Target: "test",
Identifier: "test",
},
expectedValue: true,
},
{
options: QueryOptions{},
expectedValue: false,
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
if tt.options.shouldSort() != tt.expectedValue {
t.Fatal("error shouldSort")
}
})
}
}
func TestGetMetricPosMap(t *testing.T) {
tests := []struct {
metrics []monitoring.Metric
expectedValue map[string]int
}{
{
metrics: []monitoring.Metric{
{MetricName: "one"},
{MetricName: "two"},
{MetricName: "three"},
{MetricName: "four"},
},
expectedValue: map[string]int{
"one": 0,
"two": 1,
"three": 2,
"four": 3,
},
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
if diff := cmp.Diff(getMetricPosMap(tt.metrics), tt.expectedValue); diff != "" {
t.Errorf("%T differ (-got, +want): %s", tt.expectedValue, diff)
}
})
}
}
func TestTransformMetricData(t *testing.T) {
tests := []struct {
metrics monitoringmodel.Metrics
expectedValue metering.PodsStats
}{
{
metrics: monitoringmodel.Metrics{
Results: []monitoring.Metric{
{
MetricName: "meter_pod_cpu_usage",
MetricData: monitoring.MetricData{
MetricValues: monitoring.MetricValues{
{
Metadata: map[string]string{
"pod": "pod1",
},
SumValue: "10",
},
},
},
},
{
MetricName: "meter_pod_memory_usage_wo_cache",
MetricData: monitoring.MetricData{
MetricValues: monitoring.MetricValues{
{
Metadata: map[string]string{
"pod": "pod1",
},
SumValue: "200",
},
},
},
},
{
MetricName: "meter_pod_net_bytes_transmitted",
MetricData: monitoring.MetricData{
MetricValues: monitoring.MetricValues{
{
Metadata: map[string]string{
"pod": "pod1",
},
SumValue: "300",
},
},
},
},
{
MetricName: "meter_pod_net_bytes_received",
MetricData: monitoring.MetricData{
MetricValues: monitoring.MetricValues{
{
Metadata: map[string]string{
"pod": "pod1",
},
SumValue: "300",
},
},
},
},
{
MetricName: "meter_pod_pvc_bytes_total",
MetricData: monitoring.MetricData{
MetricValues: monitoring.MetricValues{
{
Metadata: map[string]string{
"pod": "pod1",
},
SumValue: "400",
},
},
},
},
},
},
expectedValue: metering.PodsStats{
"pod1": &metering.PodStatistic{
CPUUsage: 10,
MemoryUsageWoCache: 200,
NetBytesReceived: 300,
NetBytesTransmitted: 300,
PVCBytesTotal: 400,
},
},
},
}
var tOperator tenantOperator
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
if diff := cmp.Diff(tOperator.transformMetricData(tt.metrics), tt.expectedValue); diff != "" {
t.Errorf("%T differ (-got, +want): %s", tt.expectedValue, diff)
}
})
}
}