{"id":5556,"date":"2026-07-23T15:26:38","date_gmt":"2026-07-23T22:26:38","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=5556"},"modified":"2026-07-23T15:26:40","modified_gmt":"2026-07-23T22:26:40","slug":"building-a-test-matrix-pipeline-for-couchbase-autonomous-operator","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/","title":{"rendered":"Building a Test Matrix Pipeline for Couchbase Autonomous Operator"},"content":{"rendered":"\n<h2 id=\"h-introduction\" class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Couchbase Autonomous Operator (CAO) is a Kubernetes operator that automates the deployment, management, and lifecycle of Couchbase Server clusters on Kubernetes. The team already had a powerful testing framework called <strong>CAO-Testrunner<\/strong> \u2013 a Go-based framework that uses YAML scenario files to define test actions and validations, executes them as a directed graph, and maintains shared state through a thread-safe in-memory store called <strong>TestAssets<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The project was to design and build a <strong>Test Matrix Pipeline<\/strong> \u2013 a CI\/CD pipeline that continuously validates the compatibility of CAO, Couchbase Server, and Kubernetes across multiple versions and cloud providers, catching regressions early before they reach customers.<\/p>\n\n\n\n<h2 id=\"h-the-problem\" class=\"wp-block-heading\">The Problem<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Couchbase Server weekly builds and CAO releases evolve in parallel, often on unsynchronized timelines. At the time, there was no automated way to continuously validate whether the latest unreleased Server builds worked correctly against:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Multiple released and unreleased <strong>CAO versions<\/strong><\/li>\n\n\n\n<li>Multiple <strong>Kubernetes and OpenShift versions<\/strong><\/li>\n\n\n\n<li>Multiple <strong>cloud providers<\/strong> (EKS, GKE, AKS)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This meant incompatibilities could go undetected until late in the release cycle, turning what should be a quick fix into a costly scramble. A system was needed that would automatically test every meaningful combination of these four dimensions \u2013 K8S\/OpenShift version, CAO version, Couchbase Server version, and cloud provider \u2013 whenever a new build of any component appeared.<\/p>\n\n\n\n<h2 id=\"h-designing-the-solution\" class=\"wp-block-heading\">Designing the Solution<\/h2>\n\n\n\n<h3 id=\"h-the-test-matrix\" class=\"wp-block-heading\">The Test Matrix<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The core idea is a <strong>four-dimensional version matrix<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"854\" height=\"532\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.19.39-PM.png\" alt=\"\" class=\"wp-image-5557\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.19.39-PM.png 854w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.19.39-PM-300x187.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.19.39-PM-768x478.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.19.39-PM-18x12.png 18w\" sizes=\"auto, (max-width: 854px) 100vw, 854px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The first dimension is the <strong>platform<\/strong> \u2013 this includes both vanilla Kubernetes versions and OpenShift versions, tested at the same level. The fourth dimension is the <strong>cloud provider<\/strong>, which determines the infrastructure where the cluster is provisioned (EKS, GKE, AKS, or an OpenShift-compatible environment).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When a new build of any component arrives, it becomes the <strong>trigger<\/strong>. The trigger version is fixed, and the pipeline generates all combinations from the other three dimensions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, if a new CAO build 2.9.0-115 arrives, every generated combination uses CAO 2.9.0-115, while the pipeline varies the platform, Couchbase Server version, and cloud provider. With three platform versions, three Couchbase Server versions, and three cloud providers, that produces up to 27 independent executions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The same idea applies when the trigger comes from another dimension:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"503\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.42-PM-1024x503.png\" alt=\"\" class=\"wp-image-5558\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.42-PM-1024x503.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.42-PM-300x147.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.42-PM-768x377.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.42-PM-18x9.png 18w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.42-PM.png 1202w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Visually, each trigger slices the matrix from one direction. The new build pins one axis, and the remaining axes expand around it. In the sketch below, 7.6, 8.0, and 8.1 represent Couchbase Server version families:<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"624\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.32-PM-1024x624.png\" alt=\"\" class=\"wp-image-5559\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.32-PM-1024x624.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.32-PM-300x183.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.32-PM-768x468.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.32-PM-18x12.png 18w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.20.32-PM.png 1202w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Test Tagging<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Generating the matrix is only half of the problem. The next question is which tests should run for each trigger. Running every scenario for every trigger sounds simple, but it wastes time and cloud resources, and it can make results harder to interpret.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, RBAC-related tests are important when a new Couchbase Server build arrives because changes in authentication or authorization logic can affect role behavior. They are also important when a new Couchbase Autonomous Operator (CAO) build arrives, since the operator is responsible for configuring users, roles, and security settings on the cluster. However, if the only change is a new Kubernetes patch version, RBAC tests are usually not the best signal because these behaviors are largely independent of platform-level changes. A Kubernetes-triggered run should instead focus on tests that prove the operator can install cleanly, create and reconcile clusters, manage storage, expose services, and survive platform-level changes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Similarly, a new Couchbase Server build should definitely include tests that exercise Server-facing behavior such as bucket management, rebalance, upgrades, backup, restore, query, indexing, and XDCR. A new CAO build should include operator lifecycle tests, admission controller tests, cluster create and update flows, upgrade flows, and tests that validate how CAO configures Couchbase Server features. A new Kubernetes or OpenShift build should include platform compatibility tests, networking tests, storage tests, service exposure tests, and basic end-to-end cluster health checks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is why the pipeline needed something more intelligent than a static list of scenario files. A tagging system was designed embedded directly into scenario YAML files so each test could describe when it is relevant and what part of the product it validates:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tags:\n  trigger:\n    - cao\n    - cbServer\n  minVersion:\n    k8s: 1.33\n    cbServer: 8.0.0\n  maxVersion:\n    k8s: null\n    cbServer: 7.6.11\n  subComponents:\n    cbServer:\n      - xdcr<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Each test declares:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Trigger tags<\/strong> capture the first design question: &#8220;Which type of change can this test actually give signal for?&#8221; Not every test is relevant for every change, so each test declares which component changes it is sensitive to: k8s, cao, or cbServer. This avoids running tests blindly and instead aligns execution with the source of risk. For example, admission webhook behavior is owned by the operator, so those tests run only on CAO-triggered pipelines. In contrast, XDCR correctness is driven by Couchbase Server behavior, so those tests are primarily tied to Server-triggered runs \u2013 while still running on CAO changes when operator-level interactions could affect replication. The result is a pipeline that prioritizes signal over coverage noise, ensuring that each test run answers a meaningful question about the change being introduced.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Version requirements<\/strong> capture the second design question: &#8220;Is this test even valid for this matrix combination?&#8221; Some features only exist after a specific Kubernetes or Couchbase Server version. Instead of letting those tests fail for the wrong reason on older versions, the scenario declares the minimum supported version. This makes skipped tests intentional rather than noisy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Subcomponent tags<\/strong> capture the reporting question: &#8220;Which area of the product did this test cover?&#8221; Tags such as KV, XDCR, indexing, backup, and query make it possible to build coverage views later. They also help explain a run&#8217;s results at a higher level than individual YAML file names.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A test is included in a matrix combination only when the trigger matches and all version constraints are satisfied.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pipeline Architecture<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The pipeline is implemented in <strong>Jenkins<\/strong> and orchestrated by three Go programs: dispatch, execute, and rerun.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"569\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.21.55-PM-1024x569.png\" alt=\"\" class=\"wp-image-5560\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.21.55-PM-1024x569.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.21.55-PM-300x167.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.21.55-PM-768x427.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.21.55-PM-18x10.png 18w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.21.55-PM.png 1198w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Stage 1: Dispatch<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Dispatch stage is responsible for generating the test plan.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It loads the version matrix and tag definitions, generates all matrix combinations for the given trigger, and filters the test suite for each combination based on trigger tags and minimum version constraints. The output is a dispatch-results.json file where each combination has its own pre-filtered list of scenario files to run.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"triggerType\": \"cbServer\",\n  \"triggerVersion\": \"8.0.0-3777\",\n  \"matrixExecutions\": &#091;\n    {\n      \"matrixCombo\": {\n        \"k8sVersion\": \"1.34\",\n        \"caoVersion\": \"2.9.0-314\",\n        \"cbServerVersion\": \"8.0.0-3777\",\n        \"cloudProvider\": \"aws\"\n      },\n      \"scenarioFiles\": &#091;\n        \".\/scenarios\/query\/basic-queries.yaml\",\n        \".\/scenarios\/xdcr\/network-chaos.yaml\",\n        \".\/scenarios\/xdcr\/cng-test.yaml\",\n        \".\/scenarios\/upgrades\/cbserver810_upgrade.yaml\",\n      ]\n    }\n  ]\n}<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"818\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.22.34-PM-1024x818.png\" alt=\"\" class=\"wp-image-5561\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.22.34-PM-1024x818.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.22.34-PM-300x240.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.22.34-PM-768x613.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.22.34-PM-15x12.png 15w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.22.34-PM.png 1202w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Stage 2: Execute<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Execute stage iterates through each matrix combination and runs the full lifecycle:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Provision a Kubernetes or OpenShift cluster<\/strong> \u2013 Runs a provider-specific setup scenario (e.g., aws.yaml for EKS, gcp.yaml for GKE, or an OpenShift setup) with version placeholders substituted with real values.<\/li>\n\n\n\n<li><strong>Deploy CAO<\/strong> \u2013 sets up the Admission Controller and Operator using the target CAO version.<\/li>\n\n\n\n<li><strong>Run tests<\/strong> \u2013 Executes each filtered scenario file, recording results after every single test so progress is never lost.<\/li>\n\n\n\n<li><strong>Tear down the cluster<\/strong> \u2013 Destroys the cluster regardless of test outcomes to control cloud costs.<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"756\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.03-PM-1024x756.png\" alt=\"\" class=\"wp-image-5562\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.03-PM-1024x756.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.03-PM-300x221.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.03-PM-768x567.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.03-PM-16x12.png 16w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.03-PM.png 1244w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Key design decisions in this stage:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Failure isolation<\/strong> \u2013 A failing test triggers a fresh repopulation of TestAssets to avoid a corrupted state, but execution continues to the next test. No single failure aborts the run.<\/li>\n\n\n\n<li><strong>Setup failure handling<\/strong> \u2013 If cluster provisioning fails, all tests for that combination are skipped and execution moves to teardown, but remaining matrix combinations still proceed.<\/li>\n\n\n\n<li><strong>Incremental result persistence<\/strong> \u2013 Results are written to results.json after every test, so even if Jenkins crashes mid-run, we know exactly what completed.<\/li>\n<\/ul>\n\n\n\n<h3 id=\"h-stage-3-rerun\" class=\"wp-block-heading\">Stage 3: Rerun<\/h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"992\" height=\"1024\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.58-PM-992x1024.png\" alt=\"\" class=\"wp-image-5563\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.58-PM-992x1024.png 992w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.58-PM-291x300.png 291w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.58-PM-768x792.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.58-PM-12x12.png 12w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Screenshot-2026-07-23-at-3.23.58-PM.png 1130w\" sizes=\"auto, (max-width: 992px) 100vw, 992px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Infrastructure is inherently unreliable. Jenkins agents can terminate unexpectedly, cloud API calls may time out, and cluster provisioning can fail midway. The Rerun stage is designed to recover from these interruptions without discarding progress.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When triggered with a previous build\u2019s job ID, the pipeline reads the earlier results.json, identifies tests that were never reached (i.e., no passed or failed status), and resumes execution from that point using the same Setup \u2192 Test \u2192 Teardown flow.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Only the incomplete portions of the matrix are executed again \u2013 completed tests are left untouched. To preserve traceability, rerun writes to a separate rerun-results.json, keeping the original run intact as a source of truth.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The outcome is a pipeline that can resume execution deterministically, even after partial failure, without duplicating work or losing prior results.<\/p>\n\n\n\n<h3 id=\"h-stage-4-results\" class=\"wp-block-heading\">Stage 4: Results<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The pipeline publishes results to Greenboard, Couchbase&#8217;s internal dashboard for tracking and analyzing test results.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Parallel Execution Challenge<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The sequential pipeline works, but testing 27+ matrix combinations with multiple tests each takes a long time when executed one after another. Naturally, the next step was to explore parallelization. This turned out to be significantly harder than expected.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why Parallel Is Hard<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Resource contention on shared clusters:<\/strong> If multiple tests run on the same Couchbase cluster, they can conflict \u2013 two tests creating a bucket with the same name, two subgraphs updating the same resource, or one test changing an eviction policy that another test depends on.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Isolation requirements vary by test:<\/strong> Some tests can safely share a Couchbase cluster (e.g., read-only queries), while others need complete isolation (e.g., XDCR setup, destructive operations). This led to a proposed tagging extension:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cb_cluster_isolation: shared | isolated\nk8s_cluster_isolation: shared | isolated\nrequires_new_cb_cluster: true | false<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Resource limits:<\/strong> Combining multiple scenario files could spawn many Couchbase clusters in a single Kubernetes cluster, potentially exhausting node resources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Result tracking complexity:<\/strong> When tests are combined into a single parent scenario graph, attributing pass\/fail to individual test files becomes significantly harder.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Approach Taken<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The idea was to build a <strong>Scenario Aggregator<\/strong> that would:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Read isolation tags from each scenario file.<\/li>\n\n\n\n<li>Group shared tests together under a single Couchbase deployment.<\/li>\n\n\n\n<li>Keep isolated tests separate with their own clusters.<\/li>\n\n\n\n<li>Generate a parent YAML that orchestrates everything using the existing graph execution engine.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code># AUTO-GENERATED by pipeline\nedges:\n  nodes:\n    # Based on \"cb_cluster_isolation\" tag:\n    # CASE1: tests that can share a CB cluster (shared)\n    - action: \"Deploy Couchbase\"\n      config:\n        overrideSpec:\n          image: \"server:8.1.0-1658\" #version injected\n        namespace: \"group-1\"\n      edges:\n        nodes:\n          # Scenario files that can share CB Cluster are appended here\n          - scenario: \"scenarios\/query\/basic_query_test.yaml\"\n          - scenario: \"scenarios\/bucket\/bucket_policy_test.yaml\"\n\n    # CASE2: tests that NEED their own CB cluster (isolated)\n    - scenario: \"scenarios\/xdcr\/basic-xdcr.yaml\" \n      #(assuming the file has \"Deploy CB\" action. If there is flag requires_new_cb_cluster=true, we wrap this scenario with \"Deploy CB\" action.)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This became one of the most interesting systems design problems in the project: balancing test throughput against isolation guarantees.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The Test Matrix Pipeline provides the CAO team with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Automated compatibility validation<\/strong> across the full K8S\/OpenShift x CAO x CB Server x Cloud Provider matrix whenever a new build of any component is available<\/li>\n\n\n\n<li><strong>Early regression detection<\/strong> that catches incompatibilities before they compound into release blockers<\/li>\n\n\n\n<li><strong>Selective test execution<\/strong> through test tagging, avoiding wasted compute on irrelevant tests<\/li>\n\n\n\n<li><strong>Resilient execution<\/strong> with built-in recovery from infrastructure failures<\/li>\n\n\n\n<li><strong>Clear visibility<\/strong> into test results across all version combinations<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This pipeline dramatically increases testing efficiency and confidence in the Couchbase Autonomous Operator&#8217;s compatibility.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Couchbase Autonomous Operator (CAO) is a Kubernetes operator that automates the deployment, management, and lifecycle of Couchbase Server clusters on Kubernetes. The team already had a powerful testing framework called CAO-Testrunner \u2013 a Go-based framework that uses YAML scenario files to define test actions and validations, executes them as a directed graph, and maintains [&hellip;]<\/p>\n","protected":false},"author":85712,"featured_media":5564,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_acf":"","footnotes":""},"categories":[320],"tags":[],"ppma_author":[1045],"class_list":["post-5556","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-autonomous-operator"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Building a Test Matrix Pipeline for Couchbase Autonomous Operator - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a Test Matrix Pipeline for Couchbase Autonomous Operator\" \/>\n<meta property=\"og:description\" content=\"Introduction Couchbase Autonomous Operator (CAO) is a Kubernetes operator that automates the deployment, management, and lifecycle of Couchbase Server clusters on Kubernetes. The team already had a powerful testing framework called CAO-Testrunner \u2013 a Go-based framework that uses YAML scenario files to define test actions and validations, executes them as a directed graph, and maintains [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-23T22:26:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-23T22:26:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Building-a-Test-Matrix-Pipeline-1024x536.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"536\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tarun Elangovan, Software Engineering Intern\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tarun Elangovan, Software Engineering Intern\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/\"},\"author\":{\"name\":\"Tarun Elangovan, Software Engineering Intern\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/706695b0389b0a9d29df354a99a3364d\"},\"headline\":\"Building a Test Matrix Pipeline for Couchbase Autonomous Operator\",\"datePublished\":\"2026-07-23T22:26:38+00:00\",\"dateModified\":\"2026-07-23T22:26:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/\"},\"wordCount\":1668,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/07\\\/Building-a-Test-Matrix-Pipeline.png\",\"articleSection\":[\"Couchbase Autonomous Operator\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/\",\"name\":\"Building a Test Matrix Pipeline for Couchbase Autonomous Operator - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/07\\\/Building-a-Test-Matrix-Pipeline.png\",\"datePublished\":\"2026-07-23T22:26:38+00:00\",\"dateModified\":\"2026-07-23T22:26:40+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/07\\\/Building-a-Test-Matrix-Pipeline.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/07\\\/Building-a-Test-Matrix-Pipeline.png\",\"width\":2400,\"height\":1256},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building a Test Matrix Pipeline for Couchbase Autonomous Operator\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"width\":\"1024\",\"height\":\"1024\",\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/706695b0389b0a9d29df354a99a3364d\",\"name\":\"Tarun Elangovan, Software Engineering Intern\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/07\\\/Tarun-Elangovan.pngeea88cd0fb02e1d93d7de73ee474613d\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/07\\\/Tarun-Elangovan.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/07\\\/Tarun-Elangovan.png\",\"caption\":\"Tarun Elangovan, Software Engineering Intern\"},\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/author\\\/tarun\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Building a Test Matrix Pipeline for Couchbase Autonomous Operator - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/","og_locale":"en_US","og_type":"article","og_title":"Building a Test Matrix Pipeline for Couchbase Autonomous Operator","og_description":"Introduction Couchbase Autonomous Operator (CAO) is a Kubernetes operator that automates the deployment, management, and lifecycle of Couchbase Server clusters on Kubernetes. The team already had a powerful testing framework called CAO-Testrunner \u2013 a Go-based framework that uses YAML scenario files to define test actions and validations, executes them as a directed graph, and maintains [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/","og_site_name":"The Couchbase Blog","article_published_time":"2026-07-23T22:26:38+00:00","article_modified_time":"2026-07-23T22:26:40+00:00","og_image":[{"width":1024,"height":536,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Building-a-Test-Matrix-Pipeline-1024x536.png","type":"image\/png"}],"author":"Tarun Elangovan, Software Engineering Intern","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Tarun Elangovan, Software Engineering Intern","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/"},"author":{"name":"Tarun Elangovan, Software Engineering Intern","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/706695b0389b0a9d29df354a99a3364d"},"headline":"Building a Test Matrix Pipeline for Couchbase Autonomous Operator","datePublished":"2026-07-23T22:26:38+00:00","dateModified":"2026-07-23T22:26:40+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/"},"wordCount":1668,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Building-a-Test-Matrix-Pipeline.png","articleSection":["Couchbase Autonomous Operator"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/","url":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/","name":"Building a Test Matrix Pipeline for Couchbase Autonomous Operator - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Building-a-Test-Matrix-Pipeline.png","datePublished":"2026-07-23T22:26:38+00:00","dateModified":"2026-07-23T22:26:40+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Building-a-Test-Matrix-Pipeline.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Building-a-Test-Matrix-Pipeline.png","width":2400,"height":1256},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/building-a-test-matrix-pipeline-for-couchbase-autonomous-operator\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Building a Test Matrix Pipeline for Couchbase Autonomous Operator"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","width":"1024","height":"1024","caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/706695b0389b0a9d29df354a99a3364d","name":"Tarun Elangovan, Software Engineering Intern","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Tarun-Elangovan.pngeea88cd0fb02e1d93d7de73ee474613d","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Tarun-Elangovan.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Tarun-Elangovan.png","caption":"Tarun Elangovan, Software Engineering Intern"},"url":"https:\/\/www.couchbase.com\/blog\/author\/tarun\/"}]}},"acf":[],"authors":[{"term_id":1045,"user_id":85712,"is_guest":0,"slug":"tarun","display_name":"Tarun Elangovan, Software Engineering Intern","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Tarun-Elangovan.png","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/07\/Tarun-Elangovan.png"},"author_category":"1","first_name":"Tarun","last_name":"Elangovan","user_url":"","job_title":"","description":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/5556","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/85712"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=5556"}],"version-history":[{"count":1,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/5556\/revisions"}],"predecessor-version":[{"id":5565,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/5556\/revisions\/5565"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/5564"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=5556"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=5556"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=5556"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=5556"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}