|
5 | 5 | "testing" |
6 | 6 |
|
7 | 7 | "api.audius.co/api/dbv1" |
| 8 | + "api.audius.co/database" |
8 | 9 | "api.audius.co/trashid" |
9 | 10 | "github.com/stretchr/testify/assert" |
10 | 11 | ) |
@@ -247,3 +248,204 @@ func TestGetUserTracksInvalidParams(t *testing.T) { |
247 | 248 | status, _ = testGet(t, app, url) |
248 | 249 | assert.Equal(t, 400, status) |
249 | 250 | } |
| 251 | + |
| 252 | +func TestGetUserTracksWithGateConditionFilter(t *testing.T) { |
| 253 | + app := emptyTestApp(t) |
| 254 | + fixtures := testTrackGateFixtures() |
| 255 | + database.Seed(app.pool.Replicas[0], fixtures) |
| 256 | + |
| 257 | + var userTracksResponse struct { |
| 258 | + Data []dbv1.FullTrack |
| 259 | + } |
| 260 | + |
| 261 | + baseUrl := fmt.Sprintf("/v1/full/users/%s/tracks", trashid.MustEncodeHashID(600)) |
| 262 | + |
| 263 | + // Test without filter - should return all tracks |
| 264 | + status, _ := testGet(t, app, baseUrl, &userTracksResponse) |
| 265 | + assert.Equal(t, 200, status) |
| 266 | + assert.Equal(t, 6, len(userTracksResponse.Data)) |
| 267 | + |
| 268 | + // Test filter for ungated tracks only |
| 269 | + url := fmt.Sprintf("%s?gate_condition=ungated", baseUrl) |
| 270 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 271 | + assert.Equal(t, 200, status) |
| 272 | + assert.Equal(t, 1, len(userTracksResponse.Data)) |
| 273 | + assert.Equal(t, trashid.MustEncodeHashID(800), userTracksResponse.Data[0].ID) |
| 274 | + |
| 275 | + // Test filter for usdc_purchase gated tracks |
| 276 | + url = fmt.Sprintf("%s?gate_condition=usdc_purchase", baseUrl) |
| 277 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 278 | + assert.Equal(t, 200, status) |
| 279 | + assert.Equal(t, 1, len(userTracksResponse.Data)) |
| 280 | + assert.Equal(t, trashid.MustEncodeHashID(801), userTracksResponse.Data[0].ID) |
| 281 | + |
| 282 | + // Test filter for follow gated tracks |
| 283 | + url = fmt.Sprintf("%s?gate_condition=follow", baseUrl) |
| 284 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 285 | + assert.Equal(t, 200, status) |
| 286 | + assert.Equal(t, 1, len(userTracksResponse.Data)) |
| 287 | + assert.Equal(t, trashid.MustEncodeHashID(802), userTracksResponse.Data[0].ID) |
| 288 | + |
| 289 | + // Test filter for tip gated tracks |
| 290 | + url = fmt.Sprintf("%s?gate_condition=tip", baseUrl) |
| 291 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 292 | + assert.Equal(t, 200, status) |
| 293 | + assert.Equal(t, 1, len(userTracksResponse.Data)) |
| 294 | + assert.Equal(t, trashid.MustEncodeHashID(803), userTracksResponse.Data[0].ID) |
| 295 | + |
| 296 | + // Test filter for nft gated tracks |
| 297 | + url = fmt.Sprintf("%s?gate_condition=nft", baseUrl) |
| 298 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 299 | + assert.Equal(t, 200, status) |
| 300 | + assert.Equal(t, 1, len(userTracksResponse.Data)) |
| 301 | + assert.Equal(t, trashid.MustEncodeHashID(804), userTracksResponse.Data[0].ID) |
| 302 | + |
| 303 | + // Test filter for token gated tracks |
| 304 | + url = fmt.Sprintf("%s?gate_condition=token", baseUrl) |
| 305 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 306 | + assert.Equal(t, 200, status) |
| 307 | + assert.Equal(t, 1, len(userTracksResponse.Data)) |
| 308 | + assert.Equal(t, trashid.MustEncodeHashID(805), userTracksResponse.Data[0].ID) |
| 309 | + |
| 310 | + // Test multiple gate conditions (usdc_purchase OR tip) |
| 311 | + url = fmt.Sprintf("%s?gate_condition=usdc_purchase&gate_condition=tip", baseUrl) |
| 312 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 313 | + assert.Equal(t, 200, status) |
| 314 | + assert.Equal(t, 2, len(userTracksResponse.Data)) |
| 315 | + |
| 316 | + // Test multiple gate conditions (ungated OR follow OR nft) |
| 317 | + url = fmt.Sprintf("%s?gate_condition=ungated&gate_condition=follow&gate_condition=nft", baseUrl) |
| 318 | + status, _ = testGet(t, app, url, &userTracksResponse) |
| 319 | + assert.Equal(t, 200, status) |
| 320 | + assert.Equal(t, 3, len(userTracksResponse.Data)) |
| 321 | +} |
| 322 | + |
| 323 | +func testTrackGateFixtures() map[string][]map[string]any { |
| 324 | + return map[string][]map[string]any{ |
| 325 | + "users": { |
| 326 | + { |
| 327 | + "user_id": 600, |
| 328 | + "handle": "gatedtrackstester", |
| 329 | + "handle_lc": "gatedtrackstester", |
| 330 | + "wallet": "0xd4302f79457d5f5fcd54afd9e5a1a399723e7c30", |
| 331 | + }, |
| 332 | + }, |
| 333 | + "tracks": { |
| 334 | + { |
| 335 | + "track_id": 800, |
| 336 | + "owner_id": 600, |
| 337 | + "title": "Ungated Track", |
| 338 | + "is_stream_gated": false, |
| 339 | + "created_at": "2021-01-01 00:00:00", |
| 340 | + }, |
| 341 | + { |
| 342 | + "track_id": 801, |
| 343 | + "owner_id": 600, |
| 344 | + "title": "USDC Purchase Gated Track", |
| 345 | + "is_stream_gated": true, |
| 346 | + "stream_conditions": map[string]any{ |
| 347 | + "usdc_purchase": map[string]any{ |
| 348 | + "price": 100.0, |
| 349 | + "splits": []map[string]any{ |
| 350 | + { |
| 351 | + "user_id": 600, |
| 352 | + "percentage": 100.0, |
| 353 | + }, |
| 354 | + }, |
| 355 | + }, |
| 356 | + }, |
| 357 | + "created_at": "2021-01-02 00:00:00", |
| 358 | + }, |
| 359 | + { |
| 360 | + "track_id": 802, |
| 361 | + "owner_id": 600, |
| 362 | + "title": "Follow Gated Track", |
| 363 | + "is_stream_gated": true, |
| 364 | + "stream_conditions": map[string]any{"follow_user_id": 600}, |
| 365 | + "created_at": "2021-01-03 00:00:00", |
| 366 | + }, |
| 367 | + { |
| 368 | + "track_id": 803, |
| 369 | + "owner_id": 600, |
| 370 | + "title": "Tip Gated Track", |
| 371 | + "is_stream_gated": true, |
| 372 | + "stream_conditions": map[string]any{"tip_user_id": 600}, |
| 373 | + "created_at": "2021-01-04 00:00:00", |
| 374 | + }, |
| 375 | + { |
| 376 | + "track_id": 804, |
| 377 | + "owner_id": 600, |
| 378 | + "title": "NFT Gated Track", |
| 379 | + "is_stream_gated": true, |
| 380 | + "stream_conditions": map[string]any{ |
| 381 | + "nft_collection": map[string]any{ |
| 382 | + "chain": "eth", |
| 383 | + "address": "0x1234567890123456789012345678901234567890", |
| 384 | + }, |
| 385 | + }, |
| 386 | + "created_at": "2021-01-05 00:00:00", |
| 387 | + }, |
| 388 | + { |
| 389 | + "track_id": 805, |
| 390 | + "owner_id": 600, |
| 391 | + "title": "Token Gated Track", |
| 392 | + "is_stream_gated": true, |
| 393 | + "stream_conditions": map[string]any{ |
| 394 | + "token_gate": map[string]any{ |
| 395 | + "token_mint": "7i5KKsX2weiTkry7jA4ZwSuXGhs5eJBEjY8vVxR4pfRx", |
| 396 | + "token_amount": 100, |
| 397 | + }, |
| 398 | + }, |
| 399 | + "created_at": "2021-01-06 00:00:00", |
| 400 | + }, |
| 401 | + }, |
| 402 | + } |
| 403 | +} |
| 404 | + |
| 405 | +func TestBuildGateConditionFilter(t *testing.T) { |
| 406 | + // Test with no conditions |
| 407 | + result := buildGateConditionFilter([]string{}) |
| 408 | + assert.Equal(t, "", result) |
| 409 | + |
| 410 | + // Test with single ungated condition |
| 411 | + result = buildGateConditionFilter([]string{"ungated"}) |
| 412 | + assert.Contains(t, result, "t.is_stream_gated = false") |
| 413 | + |
| 414 | + // Test with single usdc_purchase condition |
| 415 | + result = buildGateConditionFilter([]string{"usdc_purchase"}) |
| 416 | + assert.Contains(t, result, "t.is_stream_gated = true") |
| 417 | + assert.Contains(t, result, "t.stream_conditions->>'usdc_purchase' IS NOT NULL") |
| 418 | + |
| 419 | + // Test with single follow condition |
| 420 | + result = buildGateConditionFilter([]string{"follow"}) |
| 421 | + assert.Contains(t, result, "t.stream_conditions->>'follow_user_id' IS NOT NULL") |
| 422 | + |
| 423 | + // Test with single tip condition |
| 424 | + result = buildGateConditionFilter([]string{"tip"}) |
| 425 | + assert.Contains(t, result, "t.stream_conditions->>'tip_user_id' IS NOT NULL") |
| 426 | + |
| 427 | + // Test with single nft condition |
| 428 | + result = buildGateConditionFilter([]string{"nft"}) |
| 429 | + assert.Contains(t, result, "t.stream_conditions->>'nft_collection' IS NOT NULL") |
| 430 | + |
| 431 | + // Test with single token condition |
| 432 | + result = buildGateConditionFilter([]string{"token"}) |
| 433 | + assert.Contains(t, result, "t.stream_conditions->>'token_gate' IS NOT NULL") |
| 434 | + |
| 435 | + // Test with multiple conditions |
| 436 | + result = buildGateConditionFilter([]string{"ungated", "usdc_purchase"}) |
| 437 | + assert.Contains(t, result, "t.is_stream_gated = false") |
| 438 | + assert.Contains(t, result, "t.stream_conditions->>'usdc_purchase' IS NOT NULL") |
| 439 | + assert.Contains(t, result, " OR ") |
| 440 | + |
| 441 | + // Test with invalid condition (should be ignored) |
| 442 | + result = buildGateConditionFilter([]string{"invalid_condition"}) |
| 443 | + assert.Equal(t, "", result) |
| 444 | + |
| 445 | + // Test with mix of valid and invalid conditions |
| 446 | + result = buildGateConditionFilter([]string{"follow", "invalid", "tip"}) |
| 447 | + assert.Contains(t, result, "t.stream_conditions->>'follow_user_id' IS NOT NULL") |
| 448 | + assert.Contains(t, result, "t.stream_conditions->>'tip_user_id' IS NOT NULL") |
| 449 | + assert.Contains(t, result, " OR ") |
| 450 | + assert.NotContains(t, result, "invalid") |
| 451 | +} |
0 commit comments