github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/utilization/utilization_test.go (about)

     1  package utilization
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"net/http"
     8  	"testing"
     9  
    10  	"github.com/lulzWill/go-agent/internal/crossagent"
    11  	"github.com/lulzWill/go-agent/internal/logger"
    12  )
    13  
    14  func TestJSONMarshalling(t *testing.T) {
    15  	ramInitializer := new(uint64)
    16  	*ramInitializer = 1024
    17  	actualProcessors := 4
    18  	configProcessors := 16
    19  	u := Data{
    20  		MetadataVersion:   metadataVersion,
    21  		LogicalProcessors: &actualProcessors,
    22  		RAMMiB:            ramInitializer,
    23  		Hostname:          "localhost",
    24  		Vendors: &vendors{
    25  			AWS: &aws{
    26  				InstanceID:       "8BADFOOD",
    27  				InstanceType:     "t2.micro",
    28  				AvailabilityZone: "us-west-1",
    29  			},
    30  			Docker: &docker{ID: "47cbd16b77c50cbf71401"},
    31  		},
    32  		Config: &override{
    33  			LogicalProcessors: &configProcessors,
    34  		},
    35  	}
    36  
    37  	expect := `{
    38  	"metadata_version": 3,
    39  	"logical_processors": 4,
    40  	"total_ram_mib": 1024,
    41  	"hostname": "localhost",
    42  	"vendors": {
    43  		"aws": {
    44  			"instanceId": "8BADFOOD",
    45  			"instanceType": "t2.micro",
    46  			"availabilityZone": "us-west-1"
    47  		},
    48  		"docker": {
    49  			"id": "47cbd16b77c50cbf71401"
    50  		}
    51  	},
    52  	"config": {
    53  		"logical_processors": 16
    54  	}
    55  }`
    56  
    57  	j, err := json.MarshalIndent(u, "", "\t")
    58  	if err != nil {
    59  		t.Error(err)
    60  	}
    61  	if string(j) != expect {
    62  		t.Errorf("strings don't match; \nexpected: %s\n  actual: %s\n", expect, string(j))
    63  	}
    64  
    65  	// Test that we marshal not-present values to nil.
    66  	u.RAMMiB = nil
    67  	u.Hostname = ""
    68  	u.Config = nil
    69  	expect = `{
    70  	"metadata_version": 3,
    71  	"logical_processors": 4,
    72  	"total_ram_mib": null,
    73  	"hostname": "",
    74  	"vendors": {
    75  		"aws": {
    76  			"instanceId": "8BADFOOD",
    77  			"instanceType": "t2.micro",
    78  			"availabilityZone": "us-west-1"
    79  		},
    80  		"docker": {
    81  			"id": "47cbd16b77c50cbf71401"
    82  		}
    83  	}
    84  }`
    85  
    86  	j, err = json.MarshalIndent(u, "", "\t")
    87  	if err != nil {
    88  		t.Error(err)
    89  	}
    90  	if string(j) != expect {
    91  		t.Errorf("strings don't match; \nexpected: %s\n  actual: %s\n", expect, string(j))
    92  	}
    93  
    94  }
    95  
    96  type errorRoundTripper struct{ error }
    97  
    98  func (e errorRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, e }
    99  
   100  // Smoke test the Gather method.
   101  func TestUtilizationHash(t *testing.T) {
   102  	config := Config{
   103  		DetectAWS:    true,
   104  		DetectAzure:  true,
   105  		DetectDocker: true,
   106  	}
   107  	client := &http.Client{
   108  		Transport: errorRoundTripper{errors.New("timed out")},
   109  	}
   110  	data := gatherWithClient(config, logger.ShimLogger{}, client)
   111  	if data.MetadataVersion == 0 ||
   112  		nil == data.LogicalProcessors ||
   113  		0 == *data.LogicalProcessors ||
   114  		data.RAMMiB == nil ||
   115  		*data.RAMMiB == 0 ||
   116  		data.Hostname == "" {
   117  		t.Errorf("utilization data unexpected fields: %+v", data)
   118  	}
   119  }
   120  
   121  func TestOverrideFromConfig(t *testing.T) {
   122  	testcases := []struct {
   123  		config Config
   124  		expect string
   125  	}{
   126  		{Config{}, `null`},
   127  		{Config{LogicalProcessors: 16}, `{"logical_processors":16}`},
   128  		{Config{TotalRAMMIB: 1024}, `{"total_ram_mib":1024}`},
   129  		{Config{BillingHostname: "localhost"}, `{"hostname":"localhost"}`},
   130  		{Config{
   131  			LogicalProcessors: 16,
   132  			TotalRAMMIB:       1024,
   133  			BillingHostname:   "localhost",
   134  		}, `{"logical_processors":16,"total_ram_mib":1024,"hostname":"localhost"}`},
   135  	}
   136  
   137  	for _, tc := range testcases {
   138  		ov := overrideFromConfig(tc.config)
   139  		js, err := json.Marshal(ov)
   140  		if nil != err {
   141  			t.Error(tc.expect, err)
   142  			continue
   143  		}
   144  		if string(js) != tc.expect {
   145  			t.Error(tc.expect, string(js))
   146  		}
   147  	}
   148  }
   149  
   150  type utilizationCrossAgentTestcase struct {
   151  	Name              string          `json:"testname"`
   152  	RAMMIB            *uint64         `json:"input_total_ram_mib"`
   153  	LogicalProcessors *int            `json:"input_logical_processors"`
   154  	Hostname          string          `json:"input_hostname"`
   155  	BootID            string          `json:"input_boot_id"`
   156  	AWSID             string          `json:"input_aws_id"`
   157  	AWSType           string          `json:"input_aws_type"`
   158  	AWSZone           string          `json:"input_aws_zone"`
   159  	AzureLocation     string          `json:"input_azure_location"`
   160  	AzureName         string          `json:"input_azure_name"`
   161  	AzureID           string          `json:"input_azure_id"`
   162  	AzureSize         string          `json:"input_azure_size"`
   163  	GCPID             json.Number     `json:"input_gcp_id"`
   164  	GCPType           string          `json:"input_gcp_type"`
   165  	GCPName           string          `json:"input_gcp_name"`
   166  	GCPZone           string          `json:"input_gcp_zone"`
   167  	PCFGUID           string          `json:"input_pcf_guid"`
   168  	PCFIP             string          `json:"input_pcf_ip"`
   169  	PCFMemLimit       string          `json:"input_pcf_mem_limit"`
   170  	ExpectedOutput    json.RawMessage `json:"expected_output_json"`
   171  	Config            struct {
   172  		LogicalProcessors json.RawMessage `json:"NEW_RELIC_UTILIZATION_LOGICAL_PROCESSORS"`
   173  		RAWMMIB           json.RawMessage `json:"NEW_RELIC_UTILIZATION_TOTAL_RAM_MIB"`
   174  		Hostname          string          `json:"NEW_RELIC_UTILIZATION_BILLING_HOSTNAME"`
   175  	} `json:"input_environment_variables"`
   176  }
   177  
   178  func crossAgentVendors(tc utilizationCrossAgentTestcase) *vendors {
   179  	v := &vendors{}
   180  
   181  	if tc.AWSID != "" && tc.AWSType != "" && tc.AWSZone != "" {
   182  		v.AWS = &aws{
   183  			InstanceID:       tc.AWSID,
   184  			InstanceType:     tc.AWSType,
   185  			AvailabilityZone: tc.AWSZone,
   186  		}
   187  		v.AWS.validate()
   188  	}
   189  
   190  	if tc.AzureLocation != "" && tc.AzureName != "" && tc.AzureID != "" && tc.AzureSize != "" {
   191  		v.Azure = &azure{
   192  			Location: tc.AzureLocation,
   193  			Name:     tc.AzureName,
   194  			VMID:     tc.AzureID,
   195  			VMSize:   tc.AzureSize,
   196  		}
   197  		v.Azure.validate()
   198  	}
   199  
   200  	if tc.GCPID.String() != "" && tc.GCPType != "" && tc.GCPName != "" && tc.GCPZone != "" {
   201  		v.GCP = &gcp{
   202  			ID:          numericString(tc.GCPID.String()),
   203  			MachineType: tc.GCPType,
   204  			Name:        tc.GCPName,
   205  			Zone:        tc.GCPZone,
   206  		}
   207  		v.GCP.validate()
   208  	}
   209  
   210  	if tc.PCFIP != "" && tc.PCFGUID != "" && tc.PCFMemLimit != "" {
   211  		v.PCF = &pcf{
   212  			InstanceGUID: tc.PCFGUID,
   213  			InstanceIP:   tc.PCFIP,
   214  			MemoryLimit:  tc.PCFMemLimit,
   215  		}
   216  		v.PCF.validate()
   217  	}
   218  
   219  	if v.isEmpty() {
   220  		return nil
   221  	}
   222  	return v
   223  }
   224  
   225  func compactJSON(js []byte) []byte {
   226  	buf := new(bytes.Buffer)
   227  	if err := json.Compact(buf, js); err != nil {
   228  		return nil
   229  	}
   230  	return buf.Bytes()
   231  }
   232  
   233  func runUtilizationCrossAgentTestcase(t *testing.T, tc utilizationCrossAgentTestcase) {
   234  	var ConfigRAWMMIB int
   235  	if nil != tc.Config.RAWMMIB {
   236  		json.Unmarshal(tc.Config.RAWMMIB, &ConfigRAWMMIB)
   237  	}
   238  	var ConfigLogicalProcessors int
   239  	if nil != tc.Config.LogicalProcessors {
   240  		json.Unmarshal(tc.Config.LogicalProcessors, &ConfigLogicalProcessors)
   241  	}
   242  
   243  	cfg := Config{
   244  		LogicalProcessors: ConfigLogicalProcessors,
   245  		TotalRAMMIB:       ConfigRAWMMIB,
   246  		BillingHostname:   tc.Config.Hostname,
   247  	}
   248  
   249  	data := &Data{
   250  		MetadataVersion:   metadataVersion,
   251  		LogicalProcessors: tc.LogicalProcessors,
   252  		RAMMiB:            tc.RAMMIB,
   253  		Hostname:          tc.Hostname,
   254  		BootID:            tc.BootID,
   255  		Vendors:           crossAgentVendors(tc),
   256  		Config:            overrideFromConfig(cfg),
   257  	}
   258  
   259  	js, err := json.Marshal(data)
   260  	if nil != err {
   261  		t.Error(tc.Name, err)
   262  	}
   263  
   264  	expect := string(compactJSON(tc.ExpectedOutput))
   265  	if string(js) != expect {
   266  		t.Error(tc.Name, string(js), expect)
   267  	}
   268  }
   269  
   270  func TestUtilizationCrossAgent(t *testing.T) {
   271  	var tcs []utilizationCrossAgentTestcase
   272  
   273  	input, err := crossagent.ReadFile(`utilization/utilization_json.json`)
   274  	if nil != err {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	err = json.Unmarshal(input, &tcs)
   279  	if nil != err {
   280  		t.Fatal(err)
   281  	}
   282  	for _, tc := range tcs {
   283  		runUtilizationCrossAgentTestcase(t, tc)
   284  	}
   285  }
   286  
   287  func TestVendorsIsEmpty(t *testing.T) {
   288  	v := &vendors{}
   289  
   290  	if !v.isEmpty() {
   291  		t.Fatal("default vendors does not register as empty")
   292  	}
   293  
   294  	v.AWS = &aws{}
   295  	v.Azure = &azure{}
   296  	v.PCF = &pcf{}
   297  	v.GCP = &gcp{}
   298  	if v.isEmpty() {
   299  		t.Fatal("non-empty vendors registers as empty")
   300  	}
   301  }