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 }