smithery.ai

write-back-testing

Implement test utilities that write test data to the source system and validate end-to-end read cycles.

First seen Mar 25, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 8,548 B
  • docs SUMMARY.md 129 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

Implement Write-Back Testing

Prerequisites

This step requires the write-back API documentation for the source system (typically found at src/databricks/labs/communityconnector/sources/{sourcename}/{sourcename}api_doc.md). If no write-back API doc is available, this step can be skipped.

Goal

Implement test utilities that write test data to the source system, then validate your connector correctly reads and ingests that data. This creates a complete write → read → verify cycle.

Only test against non-production environments. Write operations create real data in the source system.


Implementation Steps

Step 1: Create Test Utils File

Create tests/unit/sources/{sourcename}/{sourcename}testutils.py implementing the interface defined in tests/unit/sources/lakeflowconnecttest_utils.py.

The base class LakeflowConnectWriteTestUtils provides default no-op implementations for every method (returning empty lists and (False, [], {})). You only need to override the methods your source supports.

Use the write-back API documentation as your implementation guide:

  • Write endpoints and payload structure from the "Write-Back APIs" section
  • Field name transformations from the mapping table
  • Required delays from the "Write-Specific Constraints" section
  • Required fields from the endpoint documentation

Key Methods to Implement:

  • listinsertabletables(): Return table names that support write operations (only those documented in the write-back API section)
  • generaterowsandwrite(tablename, numberofrows): Generate test data and write to the source system using documented endpoints. Returns (success, writtenrows, columnmapping)
  • listdeletabletables(): Return table names that support delete testing — only for tables with cdcwithdeletes ingestion type
  • deleterows(tablename, numberofrows): Delete records and return deleted row info for verification via readtabledeletes. Returns (success, deletedrows, columnmapping)

Reference Implementation: See tests/unit/sources/example/exampletestutils.py for a complete working example.

The column_mapping Return Value:

The third element of the tuple returned by generaterowsandwrite and deleterows maps field names in writtenrows/deletedrows to field paths in records returned by the connector's readtable / readtable_deletes. The test suite uses this to verify written values appear correctly when read back.

Common patterns:

  • Names match: {"orderid": "orderid"}
  • Nested read fields: {"email": "properties.email"} — source nests fields under a parent object (e.g., HubSpot)
  • Field renaming: {"language": "userlanguage"} — connector normalizes the field name (e.g., Qualtrics userLanguage → userlanguage)

Use dot notation for nested paths. The test suite resolves them by traversing nested dicts.

Implementation Tips:

  • Initialize your API client in init using the options dict (same credentials passed to the connector)
  • Generate unique test data with timestamps/UUIDs to avoid collisions; use identifiable prefixes (e.g., test, generated)
  • Add delays after writes for eventual consistency (e.g., time.sleep(15) for Qualtrics, time.sleep(60) for HubSpot)
  • Include retry logic for transient errors (429, 500, 503)

Step 2: Update Test File

Modify tests/unit/sources/{sourcename}/test{sourcename}lakeflowconnect.py to mix in the write-back test class before the base class and set the testutilsclass attribute. The write-back tests live in their own suite (testwritebacksuite.py) so they only run when explicitly mixed in — and most of them auto-skip in simulate mode (the default), so they don't run in CI:

from databricks.labs.community_connector.sources.{source_name}.{source_name} import {SourceName}LakeflowConnect
from tests.unit.sources.{source_name}.{source_name}_test_utils import LakeflowConnectWriteTestUtils
from tests.unit.sources.test_suite import LakeflowConnectTests
from tests.unit.sources.test_write_back_suite import LakeflowConnectWriteBackTests


class Test{SourceName}Connector(LakeflowConnectWriteBackTests, LakeflowConnectTests):
    connector_class = {SourceName}LakeflowConnect
    test_utils_class = LakeflowConnectWriteTestUtils

The MRO order matters — LakeflowConnectWriteBackTests must come first so its setup_class runs and chains via super() to the base.

Reference: See tests/unit/sources/example/testexamplelakeflow_connect.py.

Step 3: Run Tests

Write-back tests that mutate the source (testwritetosource, testincrementalafterwrite, testdeleteandreaddeletes) auto-skip unless you set CONNECTORTESTMODE=live. To run them against a real source:

source .venv/bin/activate   # or: python3.10 -m venv .venv && pip install -e ".[dev]"
CONNECTOR_TEST_MODE=live \
  CONNECTOR_TEST_CONFIG_PATH=~/secrets/{source_name}.json \
  pytest tests/unit/sources/{source_name}/test_{source_name}_lakeflow_connect.py -v

When LakeflowConnectWriteBackTests is mixed in and testutilsclass is set, these tests are added to the class:

Test What it does
testlistinsertable_tables Validates that every insertable table also appears in list_tables()
testwriteto_source Calls generaterowsandwrite for each insertable table, verifies the 3-tuple return shape, success=True, non-empty rows, and non-empty columnmapping
testincrementalafter_write Does an initial read to capture the offset, writes 1 row, creates a fresh connector instance, reads from the captured offset, and verifies the written row appears using column_mapping

Step 4: Implement Delete Testing (Optional)

For connectors with cdcwithdeletes tables whose source API supports deleting records.

Methods to Override:

  1. listdeletabletables(): Return tables that support delete testing. Every table returned must have ingestiontype: "cdcwith_deletes" — the test suite validates this.
  1. deleterows(tablename, numberofrows): Recommended approach:

- Insert rows first (via generaterowsandwrite) to maintain data balance - Fetch existing records and delete them via the source API - Wait for eventual consistency - Return (success, deletedrows, columnmapping) where deletedrows contains primary key values

``python def deleterows(self, tablename: str, numberofrows: int) -> Tuple[bool, List[Dict], Dict[str, str]]: self.generaterowsandwrite(tablename, numberofrows) # Fetch and delete existing records via source API time.sleep(60) return True, [{"id": "123"}], {"id": "properties.id"} ``

Tests added:

Test What it does
testlistdeletable_tables Validates that every deletable table appears in listtables() and has ingestiontype: "cdcwithdeletes"
testdeleteandreaddeletes Deletes 1 row from the first deletable table, then verifies it appears in readtabledeletes results

Common Issues & Debugging

Write Operation Fails (400/403)

  • Verify API credentials have write permissions
  • Check source API docs for required fields
  • Validate generated data matches schema requirements

Incremental Sync Doesn't Pick Up New Data

  • Add time.sleep() after write to allow the source to commit (5–60s depending on the source)
  • The test suite creates a fresh connector instance after writing, so connectors that cap cursors at init time will observe the new data
  • Verify cursor field in new records is newer than existing data

Column Mapping Errors (written row not found in read/delete results)

  • Compare written field names vs. read field names in the returned records
  • Update column_mapping to reflect transformations (nesting, renaming)
  • Use dot notation for nested paths: {"email": "properties.email"}
  • If the connector normalizes names (e.g., camelCase to snakecase), map accordingly: {"language": "userlanguage"}
  • For delete testing, add sufficient delay after delete for eventual consistency

Test Data Conflicts

  • Use uuid.uuid4().hex[:8] in generated IDs to avoid collisions
  • Prefix test data fields with identifiable markers (e.g., test, generated)