public void write(CruiseConfig configForEdit, OutputStream output, boolean skipPreprocessingAndValidation) throws Exception {
        LOGGER.debug("[Serializing Config] Starting to write. Validation skipped? {}", skipPreprocessingAndValidation);
        MagicalGoConfigXmlLoader loader = new MagicalGoConfigXmlLoader(configCache, registry);
        if (!configForEdit.getOrigin().isLocal()) {
            throw new GoConfigInvalidException(configForEdit, "Attempted to save merged configuration with partials");
        }
        if (!skipPreprocessingAndValidation) {
            loader.preprocessAndValidate(configForEdit);
            LOGGER.debug("[Serializing Config] Done with cruise config validators.");
        }
        Document document = createEmptyCruiseConfigDocument();
        write(configForEdit, document.getRootElement(), configCache, registry);

        LOGGER.debug("[Serializing Config] XSD and DOM validation.");
        verifyXsdValid(document);
        MagicalGoConfigXmlLoader.validateDom(document.getRootElement(), registry);
        LOGGER.info("[Serializing Config] Generating config partial.");
        XmlUtils.writeXml(document, output);
        LOGGER.debug("[Serializing Config] Finished writing config partial.");
    }
@Test
    public void shouldNotDefineATrackingToolWithoutALink() {
        CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.ONE_PIPELINE);
        PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1"));
        pipelineConfig.setTrackingTool(new TrackingTool("", "regex"));
        try {
            xmlWriter.write(cruiseConfig, output, false);
            fail("should not save a trackingtool without a link");
        } catch (Exception e) {
            assertThat(e.getMessage(), containsString("Link should be populated"));
        }
    }