|
4 | 4 | package entities |
5 | 5 |
|
6 | 6 | import ( |
| 7 | + "context" |
| 8 | + "encoding/json" |
| 9 | + "net/http" |
7 | 10 | "testing" |
8 | 11 |
|
9 | 12 | "github.com/stretchr/testify/require" |
| 13 | + |
| 14 | + mock "github.com/newrelic/newrelic-client-go/v2/pkg/testhelpers" |
10 | 15 | ) |
11 | 16 |
|
12 | 17 | func TestFindTagByKey(t *testing.T) { |
@@ -190,3 +195,74 @@ func TestBuildEntitySearchNrqlQuery(t *testing.T) { |
190 | 195 | require.Contains(t, result, "type = 'APPLICATION'") |
191 | 196 | require.Contains(t, result, " AND tags.`tagKey` = 'tagValue' AND tags.`tagKey2` = 'tagValue2'") |
192 | 197 | } |
| 198 | + |
| 199 | +// TestEntityAlertViolationInt_LargeID verifies that violationIds exceeding the int32 range |
| 200 | +// (as returned by the Alerts backend for 16-digit IDs) unmarshal without overflow or error. |
| 201 | +func TestEntityAlertViolationInt_LargeID(t *testing.T) { |
| 202 | + t.Parallel() |
| 203 | + |
| 204 | + // These are real violation IDs from the bug report (NR-561784) that exceed int32 max (2,147,483,647). |
| 205 | + cases := []struct { |
| 206 | + json string |
| 207 | + want EntityAlertViolationInt |
| 208 | + }{ |
| 209 | + {`{"violationId": 1773950568354017}`, EntityAlertViolationInt(1773950568354017)}, |
| 210 | + {`{"violationId": 1777567939793015}`, EntityAlertViolationInt(1777567939793015)}, |
| 211 | + {`{"violationId": 2147483647}`, EntityAlertViolationInt(2147483647)}, // int32 max — still works |
| 212 | + {`{"violationId": 2147483648}`, EntityAlertViolationInt(2147483648)}, // one above int32 max |
| 213 | + } |
| 214 | + |
| 215 | + for _, tc := range cases { |
| 216 | + var v EntityAlertViolation |
| 217 | + err := json.Unmarshal([]byte(tc.json), &v) |
| 218 | + require.NoError(t, err, "unmarshal failed for input %s", tc.json) |
| 219 | + require.Equal(t, tc.want, v.ViolationId) |
| 220 | + } |
| 221 | +} |
| 222 | + |
| 223 | +// TestGetEntityWithContext_LargeViolationId simulates the full Terraform read path for |
| 224 | +// newrelic_synthetics_monitor: a mock NerdGraph server returns a SyntheticMonitorEntity |
| 225 | +// with a 16-digit violationId, and GetEntityWithContext must parse it without error. |
| 226 | +// This reproduces the crash reported in NR-561784 on 32-bit platforms where |
| 227 | +// EntityAlertViolationInt was int (32-bit) instead of int64. |
| 228 | +func TestGetEntityWithContext_LargeViolationId(t *testing.T) { |
| 229 | + t.Parallel() |
| 230 | + |
| 231 | + // Real violation IDs from the bug report that overflow int32. |
| 232 | + const violationID int64 = 1773950568354017 |
| 233 | + |
| 234 | + mockResponse := `{ |
| 235 | + "data": { |
| 236 | + "actor": { |
| 237 | + "entity": { |
| 238 | + "__typename": "SyntheticMonitorEntity", |
| 239 | + "guid": "MTAwMjMzMjUwOHxTWU5USHxNT05JVE9SfDEyMzQ1Njc4", |
| 240 | + "name": "test-monitor", |
| 241 | + "recentAlertViolations": [ |
| 242 | + { |
| 243 | + "violationId": 1773950568354017, |
| 244 | + "label": "Synthetics monitor test-monitor", |
| 245 | + "level": "CRITICAL", |
| 246 | + "alertSeverity": "CRITICAL" |
| 247 | + } |
| 248 | + ] |
| 249 | + } |
| 250 | + } |
| 251 | + } |
| 252 | + }` |
| 253 | + |
| 254 | + ts := mock.NewMockServer(t, mockResponse, http.StatusOK) |
| 255 | + defer ts.Close() |
| 256 | + |
| 257 | + cfg := mock.NewTestConfig(t, ts) |
| 258 | + client := New(cfg) |
| 259 | + |
| 260 | + entity, err := client.GetEntityWithContext(context.Background(), "MTAwMjMzMjUwOHxTWU5USHxNT05JVE9SfDEyMzQ1Njc4") |
| 261 | + require.NoError(t, err) |
| 262 | + require.NotNil(t, entity) |
| 263 | + |
| 264 | + synthEntity, ok := (*entity).(*SyntheticMonitorEntity) |
| 265 | + require.True(t, ok, "expected *SyntheticMonitorEntity, got %T", *entity) |
| 266 | + require.Len(t, synthEntity.RecentAlertViolations, 1) |
| 267 | + require.Equal(t, EntityAlertViolationInt(violationID), synthEntity.RecentAlertViolations[0].ViolationId) |
| 268 | +} |
0 commit comments