Skip to content

Commit 4971444

Browse files
refactor(audience): return Task from DeleteData (SDK-147)
DeleteData fires a backend DELETE for GDPR erasure but returned void, so callers had no handle to know when the erasure completed or failed. FlushAsync returns Task for the same reason - symmetrising the lifecycle methods on the singleton. - Public signature becomes `public static Task DeleteData(string userId = null)`. - All early-return paths (not initialised, no config, no anonymousId) return Task.CompletedTask. - The hot path's Task.Run is just returned directly instead of discarded. No change to the actual HTTP request, error surfacing, or anonymousId-file-side-effect-avoidance contract. - Callers that want fire-and-forget still get it by ignoring the return value; callers that want to gate on completion can now await. Existing void-discarding call sites continue to compile. Two new tests: awaited task completes after DELETE dispatch, and the pre-Init guard returns Task.CompletedTask. 158 passing. Linear: SDK-147 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2710381 commit 4971444

2 files changed

Lines changed: 38 additions & 6 deletions

File tree

src/Packages/Audience/Runtime/ImmutableAudience.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,16 @@ public static void Reset()
230230
Identity.Reset(config.PersistentDataPath!);
231231
}
232232

233-
// Ask the backend to erase this player's data.
234-
public static void DeleteData(string? userId = null)
233+
// Ask the backend to erase this player's data. Returns a task the
234+
// caller can await to know when the request is acknowledged, or
235+
// discard for fire-and-forget.
236+
public static Task DeleteData(string? userId = null)
235237
{
236-
if (!_initialized) return;
238+
if (!_initialized) return Task.CompletedTask;
237239

238240
var config = _config;
239241
var client = _controlClient;
240-
if (config == null || client == null) return;
242+
if (config == null || client == null) return Task.CompletedTask;
241243

242244
string query;
243245
if (!string.IsNullOrEmpty(userId))
@@ -249,15 +251,15 @@ public static void DeleteData(string? userId = null)
249251
// Get, not GetOrCreate — a brand-new install must not register an ID just to delete it.
250252
var anonymousId = Identity.Get(config.PersistentDataPath!);
251253
if (string.IsNullOrEmpty(anonymousId))
252-
return;
254+
return Task.CompletedTask;
253255
query = "anonymousId=" + Uri.EscapeDataString(anonymousId);
254256
}
255257

256258
var url = Constants.DataUrl(config.PublishableKey) + "?" + query;
257259
var onError = config.OnError;
258260
var publishableKey = config.PublishableKey;
259261

260-
Task.Run(async () =>
262+
return Task.Run(async () =>
261263
{
262264
try
263265
{

src/Packages/Audience/Tests/Runtime/DeleteDataTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Linq;
45
using System.Net;
56
using System.Net.Http;
67
using System.Threading;
@@ -144,6 +145,35 @@ public void DeleteData_DoesNotCreateAnonymousIdFile()
144145
"DeleteData must not create the anonymousId file as a side effect");
145146
}
146147

148+
[Test]
149+
public async Task DeleteData_ReturnsTask_ThatCompletesAfterRequest()
150+
{
151+
var handler = new CapturingHandler();
152+
ImmutableAudience.Init(MakeConfig(handler));
153+
154+
var task = ImmutableAudience.DeleteData(userId: "player-42");
155+
Assert.IsNotNull(task, "DeleteData must return a non-null Task");
156+
157+
// Await directly: no need for the RequestSent gate when the task
158+
// already represents completion.
159+
await task;
160+
161+
Assert.IsTrue(handler.Requests.Any(r => r.Method == HttpMethod.Delete),
162+
"DELETE request must have been sent by the time the task completes");
163+
}
164+
165+
[Test]
166+
public void DeleteData_BeforeInit_ReturnsCompletedTask()
167+
{
168+
// Not initialised — must not throw, must return a completed Task.
169+
ImmutableAudience.ResetState();
170+
171+
var task = ImmutableAudience.DeleteData(userId: "player-42");
172+
173+
Assert.IsNotNull(task);
174+
Assert.IsTrue(task.IsCompleted, "DeleteData before Init must return an already-completed Task");
175+
}
176+
147177
[Test]
148178
public void DeleteData_ServerError_InvokesOnError()
149179
{

0 commit comments

Comments
 (0)