How to Test Data Sync: A Complete Guide
How to Test Data Sync: A Complete Guide
How to Test Data Sync: A Complete Guide
Testing data synchronization is a critical quality gate for any application that persists state across devices, users, or sessions. When sync fails, users see stale information, duplicate entries, or lost work, which erodes trust and can trigger support spikes. This guide walks you through why sync matters, what typically breaks, how to build a test matrix that covers happy paths, error paths, edge cases, accessibility, and security, and how to execute those tests manually and with automation. It also highlights production‑only pitfalls that only appear under real‑world load, and we provide a concise checklist you can copy into your test plan. Throughout, we show how autonomous, persona‑driven exploration (as offered by platforms like SUSA) surfaces sync defects that scripted tests often miss.
How to Test Data Sync: A Complete Guide: Why It Matters
Data sync is the invisible contract between a client and a server (or between peers) that guarantees a consistent view of shared state. When that contract breaks, the user experience degrades instantly: a note edited on a phone never appears on a tablet, a cart item added on the web disappears after checkout, or a collaborative document shows conflicting versions. The business impact includes increased churn, higher support costs, and potential data loss that may violate compliance rules (e.g., GDPR‑related audit trails).
From a testing perspective, sync introduces nondeterminism because success depends on timing, network conditions, conflict‑resolution logic, and the order in which operations arrive. Traditional functional tests that assume a static state often pass while sync bugs lurk in interleavings that only appear under load or specific device states. Therefore, a dedicated sync test strategy must treat time, concurrency, and failure injection as first‑class citizens.
How to Test Data Sync: A Complete Guide: Core Concepts and Failure Modes
Understanding the ways sync can fail helps you target tests effectively. Below are the most common failure categories, each with a brief description and typical symptoms.
| Failure Category | Root Cause | Observable Symptom |
|---|---|---|
| Lost Update | Two clients modify the same record concurrently; the server applies only one write. | User sees stale data after believing their edit saved. |
| Duplicate Creation | Client retries a create after a timeout, unaware the first request succeeded. | Multiple identical rows appear (e.g., two identical contacts). |
| Stale Read | Client reads from a local cache that has not been invalidated after a remote update. | UI shows old value despite server having newer one. |
| Conflict‑Resolution Loop | Automatic merge logic repeatedly reverts changes due to deterministic tie‑breaking. | Data oscillates between two values, causing UI flicker. |
| Network‑Induced Divergence | Partial sync succeeds (some objects transferred) then connection drops. | Subset of data is up‑to‑date while other parts lag. |
| Schema Drift | Client and server operate on different versions of the data model (e.g., added field). | Serialization errors, crashes, or silent data truncation. |
| Security Bypass | Sync endpoint trusts client‑side timestamps or IDs without validation. | Malicious client can inject or delete arbitrary records. |
| Accessibility Breakage | Sync status announcements are not exposed to screen readers. | Users relying on assistive tech miss sync errors or success cues. |
Each of these categories can be provoked with targeted test scenarios, which we detail in the matrix below.
How to Test Data Sync: A Complete Guide: Building a Comprehensive Test Matrix
A test matrix organizes scenarios by dimension (what you test) and variability (how you test it). The following table lists the core dimensions we recommend, with sub‑scenarios for each. Use this as a starting point; add product‑specific dimensions (e.g., offline‑first, multi‑tenant) as needed.
| Dimension | Happy Path | Error Path | Edge Cases | Accessibility | Security |
|---|---|---|---|---|---|
| Network | Stable Wi‑Fi, 4G/5G, successful sync after background fetch | Simulated loss mid‑sync, DNS failure, captive portal | Very high latency (>5s), intermittent packet loss, network type switch (Wi‑Fi → cellular) | Ensure toast/banner announcing sync status is announced via ARIA live region | Test that dropping packets does not expose internal IDs in error messages |
| Concurrency | Single user editing one record, sync completes | Two users editing same record simultaneously, verify conflict rule | Three‑way edit, rapid successive edits (>10 ops/sec) from same device | Verify that focus remains on edited field after conflict resolution dialog | Ensure conflict resolution does not leak other user's data in UI |
| Data Volume | Sync of <10 KB payload | Sync of payload that exceeds typical MTU (to trigger fragmentation) | Sync of >5 MB payload (large attachments, images) | Check that progress indicator respects reduced motion preferences | Validate that large payloads are not logged in plaintext |
| Timing / Clock | Device and server clocks synchronized within <1s | Simulated clock skew (+/- 5 min) | Timezone crossing during sync (device moves across zones) | Ensure any time‑based announcements are perceivable without relying on color | Test that replay attacks using old timestamps are rejected |
| Background / Foreground | App in foreground, sync triggered by user pull‑to‑refresh | App killed by OS during sync, verify resume behavior | Sync initiated while battery saver mode active, verify throttling | Confirm that background sync does not produce inaccessible notifications | Ensure background sync respects app‑only scoped tokens (no leakage) |
| Schema Evolution | Client and server on same schema version | Client newer than server (adds optional field) | Client older than server (drops required field) | Verify that error messages about schema mismatch are readable by screen readers | Test that unknown fields are stripped or cause validation failure, not silent ingestion |
| Conflict Resolution Policy | Last‑write‑wins (LWW) with vector clock | Custom merge (e.g., union of sets) | Policy that depends on external state (e.g., server‑side business rule) | Confirm that merge outcome is announced to assistive tech | Ensure policy cannot be coerced by malicious client to elevate privileges |
| Offline‑First | Make edits offline, go online, sync completes | Go offline mid‑sync, verify partial state is persisted locally | Stay offline for extended period (>24h), then sync massive backlog | Check that offline edit indicators are perceivable without sight | Validate that offline queue is encrypted at rest |
Use the matrix to generate test cases: pick one row (dimension) and one column (scenario type) to define a specific test. For example, the cell at Network × Error Path yields “Simulate loss mid‑sync and verify that the client retries with exponential backoff and does not lose data.”
Happy Path Scenarios
These verify that sync works when everything behaves as expected. Typical steps:
- Setup – Create a known baseline state on the server (via API or seed).
- Client Action – Perform a user‑initiated change (create, update, delete) on device A.
- Wait – Allow background sync to complete or trigger manual sync.
- Verification – Query device B (or refresh device A) and assert that the change appears exactly as sent, with correct timestamps and no extra fields.
Automate this with a simple loop: create N records, sync, then compare sets.
Error Path Scenarios
Here you inject failures and assert graceful handling. Common patterns:
- Network drop – Use a tool like
tc(Linux) or Network Link Conditioner (iOS) to drop packets after the client has sent a request but before receiving a response. Expect the client to queue the operation locally, show a “sync pending” indicator, and retry until success or a configurable max attempts. - Server error 500 – Mock the endpoint to return HTTP 500 for a specific request. Verify that the client surfaces an error toast, does not corrupt local state, and retries with backoff.
- Conflict – Have two clients edit the same field concurrently. Set the server’s conflict rule (e.g., LWW). After sync, assert that only the winning value persists and that the losing client receives an update or a conflict‑resolution UI prompt.
Edge Cases
Edge cases push the system beyond normal operating limits but still within spec. Examples:
- Maximum payload – Send a 4 MB base64‑encoded image in a note field. Confirm that the transfer completes, the image is viewable, and no truncation occurs.
- Clock skew – Adjust the device clock forward by 10 minutes, perform an edit, then sync. Ensure the server rejects or correctly orders the operation based on its own timestamp policy.
- Rapid toggling – Enable/disable airplane mode five times in quick succession while edits are pending. Validate that the client’s queue does not overflow and that each transition triggers a sync attempt without leaking resources.
Accessibility Considerations
Sync status must be perceivable by users who rely on assistive technology. Verify the following:
- Live Regions – Any toast, banner, or inline message that indicates “Syncing…”, “Sync complete”, or “Sync failed” uses
aria-live="polite"(orassertivefor errors). - Focus Management – After a conflict‑resolution dialog closes, focus returns to the element that triggered the sync (e.g., the save button).
- Reduced Motion – If you animate a sync spinner, respect the
prefers-reduced-motionmedia query; provide a non‑animated fallback. - Contrast – Sync indicators meet WCAG AA contrast ratios (minimum 4.5:1 for text, 3:1 for UI components).
Security Considerations
Sync endpoints are attractive targets for injection or replay attacks. Test:
- Authentication – Ensure each sync request includes a valid, short‑lived token; tampering results in 401.
- Input Validation – Send payloads with unexpected fields, extreme lengths, or malicious scripts (XSS payloads in text fields). Verify the server sanitizes or rejects them.
- Replay Protection – Capture a valid sync request, replay it after its nonce or timestamp expires; expect rejection.
- Authorization – Attempt to sync data belonging to another user (by altering object IDs); verify the server enforces ownership checks.
How to Test Data Sync: A Complete Guide: Manual Testing Approaches
Even with strong automation, manual exploratory testing remains valuable for discovering unknown unknowns, especially around UX timing and perception. Below are practical techniques you can apply today.
Exploratory Testing Checklist
Use this checklist as a lightweight guide during a session. Tick items as you verify them; note any anomalies in a shared spreadsheet or test‑management tool.
| # | Test Idea | Expected Observation | Notes |
|---|---|---|---|
| 1 | Enable airplane mode, edit a record, disable airplane mode | Edit queues locally, syncs automatically when connectivity returns, no data loss | Verify retry count |
| 2 | Rapidly toggle Wi‑Fi on/off while a large file upload is in progress | Upload pauses, resumes, completes without corruption | Observe any duplicate chunks |
| 3 | Log in as two different users on the same device (using app’s account switcher) | Each user sees only their own data; no cross‑contamination | Check that sync tokens are scoped |
| 4 | Pull‑to‑refresh while a background sync is already running | UI shows a single spinner; no double‑sync triggered | Ensure idempotency |
| 5 | Change device language to a right‑to‑left locale (e.g., Arabic) | Sync status messages mirror correctly, layout does not break | Confirm accessibility labels still read correctly |
| 6 | Increase font size to 200% in system settings | All sync‑related text scales, no clipping | Verify touch targets remain usable |
| 7 | Enable “Speak Screen” (iOS) or TalkBack (Android) and perform a sync | Spoken feedback announces “Sync started”, “Sync completed”, or error | Ensure live region works |
| 8 | Simulate a low‑battery state (<10%) and trigger a sync | Sync either defers (if battery saver blocks) or completes with a warning | Check that user is informed of deferral |
| 9 | Disconnect USB debugging while the app is running in the foreground | Sync continues unaffected (no reliance on debugger) | Confirms production‑like behavior |
| 10 | Rotate device repeatedly during sync | Orientation changes do not interrupt or duplicate sync operations | Verify state persistence across config changes |
Session‑Based Testing
Structure exploratory work into time‑boxed sessions (45‑60 min) with a clear charter. Example charter: “Investigate sync behavior under fluctuating network conditions on Android 13 using a Pixel 6.” Within the session:
- Setup – Install the latest build, log in with a test account, clear local data.
- Execute – Follow the checklist, but deviate when something interesting appears (e.g., notice a delayed toast).
- Log – Capture screen recording, network logs (via Charles/Wireshark or Android Studio Profiler), and any crash dumps.
- Debrief – After the session, summarize findings, assign severity, and create tickets for reproducible bugs.
Session notes often uncover issues that automated scripts miss, such as a race condition where a UI element briefly shows stale data before the sync completes, which only a human tester perceives as a flicker.
How to Test Data Sync: A Complete Guide: Automated Testing Strategies
Automation provides repeatability and scale. The following layers each address a different facet of sync reliability.
Unit Tests for Sync Logic
Isolate the pure functions that compute diffs, generate payloads, or apply conflict rules. Example in a hypothetical code in JavaScript omitted
- **Diff Generator** – Given two versions of an object, assert that the produced patch contains only changed fields.
- **Merge Function** – Supply concurrent edits and a conflict policy; verify the resulting object matches the expected merge.
- **Backoff Calculator** – Provide attempt number; ensure the returned delay follows the configured exponential base and jitter limits.
Keep these tests fast (< 5 ms each) and run them on every commit.
### Integration Tests with Mock Backend
Replace the real server with a controllable mock (e.g., WireMock, MSW, or a custom Express stub). This lets you simulate latency, error codes, and delayed responses without flaky network.
**Example with WireMock (Java)**
@Test
public void syncRetriesOnTransientFailure() {
// Stub the /sync endpoint to fail twice then succeed
wireMockStubFor(post(urlEqualTo("/sync"))
.willReturn(aResponse()
.withStatus(503)
.withFixedDelay(200))
.atPriority(1));
wireMockStubFor(post(urlEqualTo("/sync"))
.willReturn(aResponse()
.withStatus(200)
.withFixedDelay(0))
.atPriority(2));
// Trigger sync from the client under test
client.performSync();
// Verify that exactly three calls were made
wireMockVerify(3, postRequestedFor(urlEqualTo("/sync")));
// Assert that local state reflects the successful payload
assertEquals(expectedPayload, client.getLocalState());
}
- **Latency Injection** – Add a fixed delay of 3 seconds to mimic a slow link; assert that the client shows a spinner for at least that duration.
- **Partial Response** – Return HTTP 200 with a truncated JSON body; ensure the client detects the error, discards the partial data, and retries.
### End‑to‑End Tests Using Real Devices/Emulators
End‑to‑end (E2E) tests validate the full stack: UI → networking → backend → storage. Choose a tool that can control device state (network, locale, battery) and assert on UI after sync.
**Appium Example (Android)**
@Test
public void offlineEditSyncsAfterConnectivityRestored() throws Exception {
// 1. Go offline
((AndroidDriver) driver).setConnection(ConnectionType.NONE);
// 2. Create a note
MobileElement newNote = driver.findElement(By.id("fab_add_note"));
newNote.click();
driver.findElement(By.id("note_title")).sendKeys("Offline note");
driver.findElement(By.id("note_body")).sendKeys("Created while offline");
driver.findElement(By.id("save_button")).click();
// 3. Verify local persistence
assertTrue(driver.findElement(By.xpath("//*[@text='Offline note']")).isDisplayed());
// 4. Restore connectivity
((AndroidDriver) driver).setConnection(ConnectionType.WIFI);
// 5. Wait for sync to complete (poll for a toast or badge)
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("//*[@contains(@text,'Sync complete')]")));
// 6. Switch to second device (or use a second driver session) and confirm note appears
// (omitted for brevity)
}
- **Network Conditioning** – Use `adb shell netcfg` or Android Studio’s Network Emulator to simulate LTE, 3G, or loss.
- **Battery State** – `adb shell dumpsys battery set level 5` to test low‑battery behavior.
**Playwright Example (Web)**
test('sync recovers after intermittent network loss', async ({ page }) => {
await page.goto('https://app.example.com');
await page.click('text=New Task');
await page.fill('#title', 'Intermittent test');
await page.press('#title', 'Enter');
// Simulate loss after request sent
await page.route('**/api/sync', route => {
// First call: abort to mimic drop
if (!route.request().headers()['x-retry-count']) {
return route.abort();
}
// Second call: succeed
return route.continue();
});
await page.click('#sync-button');
await expect(page.locator('.toast-success')).toHaveText('Sync complete', { timeout: 15000 });
});
- **Mocking with Playwright** – Use `page.route` to intercept and manipulate requests, enabling fine‑grained fault injection without external tools.
### Using Autonomous Exploration (SUSA) for Sync Bugs
SUSA explores an app without pre‑written scripts, generating diverse user personas (curious, impatient, elderly, etc.) that interact with UI elements in varied orders, timings, and input styles. This approach is especially effective for surfacing sync defects that depend on:
- **Interleaving of UI actions** – A power‑user may tap rapidly, generating many concurrent edits; a novice may linger on a screen, causing delayed saves.
- **Timing‑sensitive flows** – An impatient persona may pull‑to‑refresh before a background sync finishes, testing race conditions.
- **Accessibility‑driven navigation** – An elderly persona may rely on larger touch targets and voice commands, exercising different code paths that affect how sync status is announced.
When SUSA detects a crash, ANR, or a violation (e.g., missing ARIA live region), it automatically captures the sequence of actions leading to the fault and can export an Appium (Android) or Playwright (Web) regression script. This reduces the manual effort needed to convert an exploratory finding into a repeatable test.
To enable sync‑focused exploration, give SUSA a hint about the sync‑related UI (e.g., a sync icon, a pull‑to‑refresh gesture, or a settings toggle for “Sync over Wi‑Fi only”). The platform will then prioritize exercising those controls across its persona set.
## How to Test Data Sync: A Complete Guide: Production‑Only Edge Cases
Certain problems only surface under real‑world scale, heterogeneous device fleets, or carrier‑specific behaviors. Plan to validate these in a staging environment that mimics production or via feature‑flagged canary releases.
### Network Partition Simulations
Total loss is easy to simulate, but partial partitions (where some routes work and others fail) are trickier. Use a tool like **toxiproxy** or **tc** with `netem` to corrupt ormangle` rules that drop packets based on destination port or IP prefix. Example scenario:
- The client can reach the authentication service but not the sync endpoint. Expect the app to queue sync operations, show a “sync disabled” banner, and still allow local edits. When the partition heals, the queued ops should be replayed in order.
### Clock Skew and Timezone Issues
Devices may have incorrect local time due to user misconfiguration or automatic timezone detection failures. Test by manually setting the device clock ahead/behind while keeping the server time constant. Observe whether:
- Timestamps attached to client‑generated IDs are rejected or re‑ordered.
- Conflict‑resolution logic that relies on “last write wins” behaves predictably.
- Scheduled background sync (e.g., “sync every 2 hours”) fires at the wrong wall‑clock time.
### Background Sync Throttling
Both iOS and Android impose execution limits on background work to preserve battery. Validate that your app respects these limits and gracefully degrades:
- On Android, use `JobScheduler` or `WorkManager` with constraints (e.g., `setRequiredNetworkType(NetworkType.UNMETERED)`). Verify that when the device is on a metered network, the job is deferred until an unmetered connection appears.
- On iOS, check that `BGAppRefreshTask` does not exceed the allotted background time (≈30 seconds). If the sync operation would take longer, split it into chunks and reschedule.
### Battery Optimization Interference
Manufacturers often aggressively kill background services. Test on devices from Xiaomi, OnePlus, and Samsung with battery‑saver modes enabled:
- Launch the app, start a sync, then lock the screen and wait. Use `adb shell dumpsys battery` to confirm that the sync service is still alive or that it is rescheduled correctly.
- Ensure that when the OS kills the process, the next launch resumes any pending sync from a persisted queue, not from scratch.
### Carrier‑Specific Middleware
Some mobile carriers insert proxies that modify headers (e.g., adding `X-Forwarded-For`) or compress payloads. Deploy a test SIM or use a carrier‑emulation proxy to confirm that:
- Your auth headers are not stripped or altered.
- Gzip/decompression works correctly on both request and response sides.
- The app does not rely on undocumented header values that carriers may change.
### High‑Concurrency Load from Many Devices
Simulate dozens or hundreds of devices syncing the same dataset (e.g., a shared inventory). Use a container‑orchestrated load generator (e.g., Locust or k6) that runs the sync API directly, bypassing the UI. Watch for:
- Back‑pressure responses (HTTP 429) that the client must honor.
- Server‑side conflict resolution thrashing (too many merge attempts).
- Database lock timeouts or deadlocks that manifest as 500 errors under load.
When these issues appear only under load, they often escape unit and functional tests but can be caught with a dedicated performance‑sync suite that runs nightly against a staging cluster.
## How to Test Data Sync: A Complete Guide: Tooling and Frameworks
Choosing the right instrumentation reduces flakiness and speeds feedback. Below is a quick reference table mapping platform to recommended tools for each testing layer.
| Platform | Unit / Logic | Integration (Mock) | UI / E2E | Network Conditioning | Observability |
|----------|--------------|--------------------|----------|----------------------|---------------|
| Android | JUnit + Mockito | WireMock / MockWebServer | Espresso, UIAutomator, Appium | Android Studio Network Emulator, `adb shell netcmd` | Firebase Crashlytics, Perfetto traces |
| iOS | XCTest + OCMock | Moco / SwiftWebSocket | XCUITest, Appium | Network Link Conditioner (Xcode), `tty` throttling | Firebase Crashlytics, Signposts |
| Web (SPA) | Jest, Vitest | MSW (Mock Service Worker) | Cypress, Playwright | `clumsy` (Windows), `tc` + `netem` on Linux dev container, Playwright `route` throttling | Sentry, LogRocket |
| Backend | JUnit / pytest | WireMock, Pact, Hoverfly | N/A | Service mesh fault injection (Istio, Linkerd) | OpenTelemetry, Jaeger, Prometheus |
### Logging and Observability
Effective debugging of sync issues relies on correlated logs across client, network, and server. Implement the following:
- **Correlation ID** – Generate a UUID at the start of a user‑initiated sync, attach it to every outgoing request, and propagate it through backend services. Log this ID at entry/exit points.
- **Structured Logs** – Emit JSON logs with fields: `timestamp`, `level`, `service`, `operation`, `correlationId`, `latencyMs`, `outcome`. This enables querying in ELK or Loki.
- **Metrics** – Track counters: `sync_started`, `sync_succeeded`, `sync_failed`, `sync_retries`, `conflicts_resolved`. Gauges: `pending_sync_queue_size`, `average_sync_latency`. Alert on spikes in failure rate or queue depth.
- **Distributed Tracing** – Use OpenTelemetry to span the sync flow from UI click → network request → API gateway → service → DB. Look for gaps where a span disappears (indicating a lost request).
When a sync bug appears in production, these traces let you pinpoint whether the failure originated in the client (e.g., request never sent), the network (timeout), or the server (error response, missing commit).
## How to Test Data Sync: A Complete Guide: Checklist for Release
Before tagging a release, run through this concise list. Mark each item as Pass/Fail and block the release on any Fail.
| # | Checklist Item | Pass Criteria |
|---|----------------|---------------|
| 1 | Unit test coverage for sync‑related pure functions ≥ 90% | All edge‑case branches exercised |
| 2 | Integration test suite runs against a fresh mock backend with latency injection (0 ms, 300 ms, 1500 ms) and passes | No flaky failures after 3 retries |
| 3 | E2E test on a real device/emulator verifies happy path, network loss mid‑sync, and conflict resolution | All scenarios complete within expected timeouts |
| 4 | Accessibility audit (axe‑core or similar) on sync status messages | No WCAG AA violations |
| 5 | Security scan (OWASP ZAP or similar) on sync endpoints | No high‑severity findings (auth bypass, injection) |
| 6 | Battery‑optimization test: sync completes or is deferred correctly when Battery Saver is ON | UI reflects deferral, no lost data |
| 7 | Network partition test (auth reachable, sync endpoint blocked) shows queued ops and successful replay after heal | No data loss, correct ordering |
| 8 | Load test: 100 concurrent sync requests to shared dataset results in ≤ 5% 429 responses and no server 5xx | System stays stable under load |
| 9 | Canary release: 5 % of users receive new build; monitor sync‑error rate vs baseline for 2 h | No statistically significant increase |
|10 | Rollback plan documented and tested in staging | Ability to revert within 5 min |
If any item fails, investigate, fix, and re‑run the checklist before proceeding.
## How to Test Data Sync: A Complete Guide: Closing Takeaways
Testing data synchronization is not a checklist you run once and forget; it is an ongoing discipline that blends deterministic unit tests, fault‑injected integration suites, realistic E2E scenarios, and production‑aware chaos experiments. The matrix approach ensures you cover the dimensions that actually cause bugs—network variability, concurrency, data volume, timing, schema evolution, and policy specifics—while accessibility and security checks keep the experience inclusive and safe.
Manual exploratory testing, especially when guided by a persona‑based charter, catches the subtle UX glitches that automated scripts can miss, such as a toast that appears for a single frame or a focus trap that leaves a user lost after a conflict dialog. Autonomous exploration platforms like SUSA amplify this effect by systematically exercising the app through varied behavioral models, surfacing interleavings that would take weeks of manual testing to encounter, and then exporting ready‑to‑run regression scripts.
In production, the real test begins when the app meets the unpredictable: carrier middlewares, aggressive battery savers, users with clocks set incorrectly, and spikes of concurrent users. Designing your sync layer to be observable—through correlation IDs, structured logs, metrics, and distributed tracing—turns those inevitable failures into actionable insight rather than mysterious bugs.
By combining the test matrix, layered automation, purposeful manual sessions, and rigorous observability, you ship sync features with confidence that data stays consistent, users stay informed, and your team spends less time firefighting and more time building the next feature.
---
*Keep this guide bookmarked. Return to it whenever you add a new sync pathway, adjust a conflict rule, or prepare for a major platform release.*
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free