private static void validateZones(Set<RegionName> deployments, Set<RegionName> tests, DeploymentSpec.Step step) {
        if ( ! step.steps().isEmpty()) {
            Set<RegionName> oldDeployments = Set.copyOf(deployments);
            for (DeploymentSpec.Step nested : step.steps()) {
                Set<RegionName> seenDeployments = new HashSet<>(step.isOrdered() ? deployments : oldDeployments);
                validateZones(seenDeployments, tests, nested);
                deployments.addAll(seenDeployments);
            }
        }
        else if (step.concerns(Environment.prod)) {
            if (step.isTest()) {
                RegionName region = ((DeploymentSpec.DeclaredTest) step).region();
                if ( ! deployments.contains(region))
                    throw new IllegalArgumentException("tests for prod." + region + " must be after the corresponding deployment in deployment.xml");
                if ( ! tests.add(region))
                    throw new IllegalArgumentException("tests for prod." + region + " are listed twice in deployment.xml");
            }
            else {
                RegionName region = ((DeploymentSpec.DeclaredZone) step).region().get();
                if ( ! deployments.add(region))
                    throw new IllegalArgumentException("prod." + region + " is listed twice in deployment.xml");
            }
        }
    }
Throws an IllegalArgumentException if any production deployment or test is declared multiple times,
or if any production test is declared not after its corresponding deployment.

@param deployments previously seen deployments
@param tests previously seen tests
@param step step whose members to validate
config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java