- 数据工程
- 数据集成
- ETL
- 后端
- 大数据
【免费下载链接】airbyte
Open-source data movement for ELT pipelines and AI agents — from APIs, databases & files to warehouses, lakes, and AI applications. Both self-hosted and Cloud.
本指南以airbyte-integrations/connectors/source-azure-blob-storage/integration_tests/目录下的测试体系为核心,系统讲解 Airbyte Azure Blob Storage 连接器集成测试的完整链路:如何利用 Source-Faker 生成海量随机数据、如何借助 Azurite 模拟 Azure Blob 存储服务、以及如何针对 CSV / JSONL / Parquet / Avro 四种文件格式执行参数化读取测试并断言记录数。读完本文,你将掌握该连接器集成测试的目录结构、每个环节的底层实现(含源码级证据)以及完整的测试配置写法,能够独立读懂、复现并扩展这套端到端测试方案。
集成测试概览:一套基于容器的端到端验证方案
Azure Blob Storage 连接器的集成测试不依赖真实的 Azure 云资源,而是通过Azurite(微软官方提供的 Azure 存储服务模拟器)在本地 Docker 容器中搭建一套完整的测试环境。整条测试流水线可归纳为以下四个阶段(摘自 integration_tests/README.md 中的测试套件流程定义):
各阶段职责如下:
- Generate Random CSV Files:以子进程方式调用 csv_export/main.sh,等待 3 个 CSV 文件(users / purchases / products)生成完毕;
- Docker Container Setup:在 localhost 上启动 Azurite server emulator 容器;
- Convert & upload file:读取生成的
.csv文件,将其转换为目标格式(CSV / JSONL / Parquet / Avro)后批量上传到 Azurite 容器; - Tests:使用提供的 catalog 从源读取数据,断言读取到的记录数量;
- 每个测试结束后,所有上传的文件都会被删除,保证测试环境可重复。
前置条件:跑通测试前需要准备的三个要素
原文档明确列出了运行集成测试的三项前置条件,每一项都在仓库中有对应的实体文件:
1.build_customization.py:为测试镜像安装 Docker
测试需要启动 Azurite 容器,因此连接器的 base image 必须内置 Docker CLI。build_customization.py 通过pre_connector_install钩子在镜像构建阶段完成安装:先通过apt-get安装curl与jq,再借助官方安装脚本https://get.docker.com安装 Docker。这也是 Airbyte 连接器镜像定制机制(customization)的典型用法——测试环境需要的额外运行时依赖不写进连接器本体,而是通过该文件按需注入。
2.config-*.json与configured_catalog.json:测试输入的双要件
- 配置文件:位于 integration_tests/configs/ 下,按文件格式拆分为
config_integration_csv.json、config_integration_jsonl.json、config_integration_parquet.json、config_integration_avro.json四份,分别对应四种被测格式; - Catalog:位于 integration_tests/configured_catalog.json(会话级共用),同时 integration_tests/integration_configured_catalog/configured_catalog.json 提供另一份带 JSON Schema 的 catalog,用于 Avro 文件生成时的 schema 推导。
此外,integration_tests/abnormal_states/ 目录为 avro / csv / jsonl / jsonl_newlines / parquet 提供了异常状态样本,integration_tests/expected_records/ 则保存了各格式与各 CSV 解析变体(如csv_no_header、csv_skip_rows、csv_with_nulls、csv_user_schema等)的预期记录文件,共同构成断言依据。
3. Source-Faker 配置:测试数据的生产者
测试数据由 Airbyte 的Source-Faker连接器生成,其配置文件位于 integration_tests/csv_export/secret_faker/secret_faker.json:
{ "count": 100000, "seed": 0, "parallelism": 2, "always_updated": false }其中count属性表示每个文件生成的记录数,seed用于固定随机种子以保障数据可复现,parallelism控制生成并发度。整个 CSV 生成工具集位于 integration_tests/csv_export/,其内部结构为:
configured_catalog/configured_catalog.json:指定需要输出的流(users / purchases / products);main.sh:总入口,负责调度容器与子脚本;purchases.sh/products.sh/users.sh:分别针对三个流的并行 CSV 落盘脚本。
测试数据生成:Source-Faker 到 CSV 的并行流水线
生成随机 CSV 的入口是 main.sh,其核心逻辑如下:
docker run --rm \ -v /tmp/csv/csv_export/secret_faker:/secrets \ -v /tmp/csv/csv_export/configured_catalog:/integration_tests \ airbyte/source-faker:latest read \ --config /secrets/secret_faker.json \ --catalog /integration_tests/configured_catalog.json \ | tee >(./purchases.sh) >(./products.sh) >(./users.sh) > /dev/null脚本首先将自身所在目录拷贝到/tmp/csv,随后以容器方式运行airbyte/source-faker:latest,把secret_faker.json作为--config、configured_catalog.json作为--catalog传入,执行read命令输出 Airbyte 消息流。关键技巧在于tee+ 进程替换(process substitution):输出被同时扇出到三个子脚本,每个流(users / purchases / products)并行地将 RECORDS 消息通过jq转换为 CSV 并写盘。原文档特别强调这种"按流并行处理 + 仅依赖命令行工具"的设计是为了保证处理速度。CSV 文件最终输出到/tmp/csv/目录,即users.csv、purchases.csv、products.csv。
该目录下的 csv_export/README.md 还说明了这套工具的通用价值:通过--config、--state、--catalog参数手动推进 sync,可以分块读取并存储输入数据,例如按 100GB 一批将 1TB 级别的 Faker 数据拆成多个 chunk 落地。
Azurite 模拟环境:集成测试的存储底座
容器启动方式
在 conftest.py 中,connector_setup_fixture是一个session 级别且 autouse的 fixture:它先调用generate_random_csv_with_source_faker()生成 CSV,再启动 Azurite 容器:
container = docker_client.containers.run( image="mcr.microsoft.com/azure-storage/azurite", command="azurite-blob --blobHost 0.0.0.0 -l /data --loose", name=f"azurite_integration_{uuid.uuid4().hex}", hostname="azurite", ports={10000: ("0.0.0.0", 10000), 10001: ("0.0.0.0", 10001), 10002: ("0.0.0.0", 10002)}, environment={"AZURITE_ACCOUNTS": "account1:key1"}, detach=True, )要点说明:
- 使用
mcr.microsoft.com/azure-storage/azurite官方镜像,仅启动 blob 服务(azurite-blob); - 映射 10000(Blob)、10001(Queue)、10002(Table)三个端口;
- 通过
AZURITE_ACCOUNTS=account1:key1预置测试账号与密钥; - 容器启动后
time.sleep(10)等待服务就绪,随后创建名为testcontainer的容器; - fixture 结束时执行
container.kill()与container.remove()完成清理。
仓库同时提供了 integration_tests/docker-compose.yaml,以 Compose 形式描述了同一套 Azurite 服务(含./data:/data数据卷挂载与UseDevelopmentStorage=true环境变量),方便在本地手工起停模拟环境进行调试。
客户端连接与 Docker IP 处理
conftest.py 中的get_container_client()使用BlobServiceClient(f"http://{docker_ip}:10000/account1", credential="key1")建立连接。其中docker_ip由 utils.py 的get_docker_ip()决定:当DOCKER_HOST为空或以unix://开头时返回127.0.0.1,否则从tcp://host:port形式的地址中解析出宿主机 IP。各格式的 fixture 还会把配置中的azure_blob_storage_endpoint里的localhost替换为该 IP,确保测试容器能正确访问到 Azurite。
值得一提的细节是:conftest.py 通过monkey patch覆写了 Azure SDK 的_format_shared_key_credential,使其固定返回{"account_key": "key1", "account_name": "account1"}。代码注释说明了原因——原始方法只处理localhost/127.0.0.1地址,在 Dagger 的global-docker-host网络模式下无法工作,这一改动保证了测试在 Airbyte CI 容器环境中的兼容性。
参数化测试:四种格式 × 三十个文件的记录数断言
测试主体
integration_test.py 定义了唯一的核心测试test_read_files,通过@pytest.mark.parametrize对config_csv、config_jsonl、config_parquet、config_avro四个配置 fixture 进行参数化:
@pytest.mark.parametrize( "config", [ "config_csv", "config_jsonl", "config_parquet", "config_avro", ], ) def test_read_files(configured_catalog: ConfiguredAirbyteCatalog, config: Mapping[str, Any], request): """Read 2_001_000 records in 30 files""" config = request.getfixturevalue(config) source = SourceAzureBlobStorage( SourceAzureBlobStorageStreamReader(), spec_class=SourceAzureBlobStorageSpec, catalog=configured_catalog, config=config, state=None, cursor_cls=DefaultFileBasedCursor, ) output = read(source=source, config=config, catalog=configured_catalog) assert sum(x.state.sourceStats.recordCount for x in output.state_messages) == 2_001_000从源码结构可以读出以下几点实现事实:
- 测试通过 CDK 的
airbyte_cdk.test.entrypoint_wrapper.read驱动连接器执行读取,而非直接调用流方法,因此覆盖的是从配置解析、catalog 匹配到文件读取的完整路径; - 连接器实例由
SourceAzureBlobStorage组合SourceAzureBlobStorageStreamReader构建,cursor 使用DefaultFileBasedCursor; - 断言依据是各 stream state 消息中的
stateSourceStats.recordCount之和,预期为2,001,000 条记录、30 个文件(代码注释明确标注)。
四种格式的转换与上传
每个 config fixture 的职责是:加载对应格式的配置、修正 endpoint 地址、上传 30 个文件(3 张表 × 每种格式 10 份拷贝)、测试结束后遍历删除全部 blob。以 CSV 为例:
def upload_csv_files(container_client: ContainerClient) -> None: """upload 30 csv files""" for table in ("products", "purchases", "users"): csv_large_file = open(f"/tmp/csv/{table}.csv", "rb").read() for i in range(10): container_client.upload_blob(f"test_csv_{table}_{i}.csv", csv_large_file, validate_content=False)其余三种格式的转换路径各有特点:
- JSONL:用 pandas
read_csv读取 CSV 后,通过df.to_json(..., orient="records", lines=True)转换为 JSON Lines 格式; - Parquet:同样先
read_csv,再df.to_parquet()直接序列化; - Avro:最为复杂——先从 catalog 中取出各流的 JSON Schema,映射为 Avro schema(
JSON_TO_AVRO_TYPES = {"string": "string", "integer": "long", "number": "float", "object": "record"},并处理可空联合类型与默认值),再用fastavro的parse_schema+writer写盘。
所有上传的 blob 命名遵循test_<format>_<table>_<i>.<ext>模式,与各配置文件中 stream 的globs模式一一对应(例如 CSV 流使用**/test_csv_users*.csv),这也是 glob 匹配规则能够在测试中精准命中目标文件的原因。
清理机制
每个 config fixture 在yield之后都会执行同样的收尾逻辑:
for blob in container_client.list_blobs(): container_client.delete_blob(blob.name)即测试结束后遍历容器并删除所有已上传的 blob,确保不同格式的测试之间互不干扰、环境保持干净。
配置文件参考:四种格式的完整参数说明
四种格式的配置共享同一套连接器级参数,区别集中在streams的file_type、globs与format块。以下分别给出要点:
连接器级公共参数
| 参数 | 示例值 | 说明 |
|---|---|---|
azure_blob_storage_endpoint | http://localhost:10000/account1 | Blob 服务端点,集成测试指向 Azurite |
azure_blob_storage_account_name | account1 | 存储账号名,与AZURITE_ACCOUNTS对应 |
credentials.auth_type | storage_account_key | 认证方式(测试采用账号密钥) |
azure_blob_storage_account_key | key1 | 账号密钥 |
azure_blob_storage_container_name | testcontainer | 目标容器名 |
CSV 流完整示例
以 config_integration_csv.json 中的users流为例,它展示了 CSV 解析器的完整参数面:
{ "name": "users", "file_type": "csv", "globs": ["**/test_csv_users*.csv"], "legacy_prefix": "", "validation_policy": "Emit Record", "format": { "filetype": "csv", "delimiter": ",", "quote_char": "\"", "double_quote": true, "null_values": ["", "#N/A", "#N/A N/A", "#NA", "-1.#IND", "-1.#QNAN", "-NaN", "-nan", "1.#IND", "1.#QNAN", "N/A", "NA", "NULL", "NaN", "n/a", "nan", "null"], "true_values": ["1", "True", "TRUE", "true"], "false_values": ["0", "False", "FALSE", "false"], "inference_type": "Primitive Types Only", "strings_can_be_null": false, "encoding": "utf8", "header_definition": { "header_definition_type": "From CSV" } } }参数含义:
delimiter/quote_char/double_quote:分隔符、引用符及引号内双写转义;null_values/true_values/false_values:空值、布尔真/假值的字符串识别集合(含多种大小写与 Excel/NumPy 常见占位符);inference_type:类型推断策略(测试使用Primitive Types Only);strings_can_be_null:字符串字段是否允许为 null;encoding:文件编码(utf8);header_definition.header_definition_type:表头来源(From CSV,即从文件首行读取)。
purchases与products流结构完全一致,仅name与globs不同。
JSONL / Parquet / Avro 流
- JSONL(config_integration_jsonl.json):
file_type为jsonl,format仅需{"filetype": "jsonl"},并额外支持流级参数newlines_in_values: true(允许值内包含换行符); - Parquet(config_integration_parquet.json)与Avro(config_integration_avro.json):
file_type分别为parquet/avro,format块同样只需声明filetype,因为列式格式自带 schema,无需额外解析参数。
值得注意的是,Parquet / Avro 配置中的流file_type字段写的是jsonl(见 config_integration_parquet.json 第 11 行等处),这属于测试配置中的既有取值,真正决定解析格式的是format.filetype。读者在参考这些配置编写自己的测试时,应以format.filetype为准并保持两者一致。
如何运行这套集成测试
结合 acceptance.py(声明connector_acceptance_test.plugin插件,并预留了 session 级外部依赖 setup 钩子)与上述源码,运行链路可归纳为:
- 确保 Docker 可用(集成测试会动态拉起 Azurite 容器),本地 Docker daemon 可通过 UNIX socket 或
DOCKER_HOST=tcp://...访问; - 通过连接器的测试入口(如 Airbyte CI 的
connector-tests/ pytest 对integration_tests/目录的执行)运行测试,此时connector_setup_fixture会自动完成 CSV 生成、Azurite 启动、容器创建三个初始化动作; - 四个参数化的测试用例依次执行:每个用例先上传对应格式的 30 个文件,再驱动
SourceAzureBlobStorage按 catalog 读取,最后断言recordCount总和为 2,001,000; - 每个用例结束即删除全部 blob,会话结束则销毁 Azurite 容器,环境完全自清理。
这套方案的价值在于:它用完全本地的模拟环境(Azurite)覆盖了真实存储服务的关键行为,同时以 Source-Faker 保证了数据规模与随机性,使得连接器对不同文件格式、glob 匹配、schema 推断与记录数统计的正确性能够得到稳定、可重复、无需云资源即可验证的保障。无论是排查连接器读取问题、新增文件格式支持,还是回归验证 catalog 变更,这套集成测试框架都是可以直接复用与扩展的基准。
- 数据工程
- 数据集成
- ETL
- 后端
- 大数据
【免费下载链接】airbyte
Open-source data movement for ELT pipelines and AI agents — from APIs, databases & files to warehouses, lakes, and AI applications. Both self-hosted and Cloud.
相关推荐
ToolJet 集成 Azure Blob Storage 数据源完全指南:从连接配置到六大操作实战
ToolJet 集成 Azure Blob Storage 数据源完全指南:从连接配置到六大操作实战 Azure Blob 是微软 Azure 提供的海量对象存
低代码后端前端AI 应用MCP 服务Airbyte source-k6-cloud 声明式连接器全解析:从 manifest 配置到验收测试
Airbyte source k6 cloud 声明式连接器全解析:从 manifest 配置到验收测试 本篇文章以 Airbyte 仓库中的 source k
数据工程数据集成ETL后端大数据Valdi VSCode 调试器集成测试指南:从 Android 设备连接到断点命中的端到端验证
Valdi VSCode 调试器集成测试指南:从 Android 设备连接到断点命中的端到端验证 Valdi 是一个跨平台 UI 框架,其配套的 VSCode
跨平台UI组件前端移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考