public ConfigOperateResult insertOrUpdate(String srcIp, String srcUser, ConfigInfo configInfo,
            Map<String, Object> configAdvanceInfo) {
        try {
            ConfigInfoStateWrapper configInfoState = findConfigInfoState(configInfo.getDataId(), configInfo.getGroup(),
                    configInfo.getTenant());
            if (configInfoState == null) {
                return addConfigInfo(srcIp, srcUser, configInfo, configAdvanceInfo);
            } else {
                return updateConfigInfo(configInfo, srcIp, srcUser, configAdvanceInfo);
            }
            
        } catch (Exception exception) {
            LogUtil.FATAL_LOG.error("[db-error] try to update or add config failed, {}", exception.getMessage(),
                    exception);
            throw exception;
        }
    }
@Test
    void testInsertOrUpdateOfUpdateConfigSuccess() {
        
        Map<String, Object> configAdvanceInfo = new HashMap<>();
        configAdvanceInfo.put("config_tags", "tag1,tag2");
        configAdvanceInfo.put("desc", "desc11");
        configAdvanceInfo.put("use", "use2233");
        configAdvanceInfo.put("effect", "effect222");
        configAdvanceInfo.put("type", "type3");
        configAdvanceInfo.put("schema", "schema");
        
        String dataId = "dataId";
        String group = "group";
        String tenant = "tenant";
        String content = "content132456";
        
        ConfigInfo configInfo = new ConfigInfo(dataId, group, tenant, null, content);
        String encryptedDataKey = "key34567";
        configInfo.setEncryptedDataKey(encryptedDataKey);
        //mock get config state,first and second is not null
        Mockito.when(jdbcTemplate.queryForObject(anyString(), eq(new Object[] {dataId, group, tenant}),
                eq(CONFIG_INFO_STATE_WRAPPER_ROW_MAPPER))).thenReturn(new ConfigInfoStateWrapper(), new ConfigInfoStateWrapper());
        
        //mock select config info before update
        ConfigInfoWrapper configInfoWrapperOld = new ConfigInfoWrapper();
        configInfoWrapperOld.setDataId(dataId);
        configInfoWrapperOld.setGroup(group);
        configInfoWrapperOld.setTenant(tenant);
        configInfoWrapperOld.setAppName("old_app");
        configInfoWrapperOld.setMd5("old_md5");
        configInfoWrapperOld.setId(12345678765L);
        Mockito.when(jdbcTemplate.queryForObject(anyString(), eq(new Object[] {dataId, group, tenant}), eq(CONFIG_INFO_WRAPPER_ROW_MAPPER)))
                .thenReturn(configInfoWrapperOld);
        String srcIp = "srcIp";
        String srcUser = "srcUser";
        //mock update config info
        Mockito.when(jdbcTemplate.update(eq(externalConfigInfoPersistService.mapperManager.findMapper(dataSourceService.getDataSourceType(),
                                TableConstant.CONFIG_INFO)
                        .update(Arrays.asList("content", "md5", "src_ip", "src_user", "gmt_modified@NOW()", "app_name", "c_desc", "c_use",
                                "effect", "type", "c_schema", "encrypted_data_key"), Arrays.asList("data_id", "group_id", "tenant_id"))),
                eq(configInfo.getContent()), eq(configInfo.getMd5()), eq(srcIp), eq(srcUser), eq(configInfoWrapperOld.getAppName()),
                eq(configAdvanceInfo.get("desc")), eq(configAdvanceInfo.get("use")), eq(configAdvanceInfo.get("effect")),
                eq(configAdvanceInfo.get("type")), eq(configAdvanceInfo.get("schema")), eq(encryptedDataKey), eq(configInfo.getDataId()),
                eq(configInfo.getGroup()), eq(tenant))).thenReturn(1);
        
        //mock insert config tags.
        Mockito.when(jdbcTemplate.update(eq(externalConfigInfoPersistService.mapperManager.findMapper(dataSourceService.getDataSourceType(),
                                TableConstant.CONFIG_TAGS_RELATION)
                        .insert(Arrays.asList("id", "tag_name", "tag_type", "data_id", "group_id", "tenant_id"))), eq(12345678765L), anyString(),
                eq(StringUtils.EMPTY), eq(dataId), eq(group), eq(tenant))).thenReturn(1);
        
        //mock insert his config info
        Mockito.doNothing().when(historyConfigInfoPersistService)
                .insertConfigHistoryAtomic(eq(configInfoWrapperOld.getId()), eq(configInfo), eq(srcIp), eq(srcUser), any(Timestamp.class),
                        eq("I"));
        
        externalConfigInfoPersistService.insertOrUpdate(srcIp, srcUser, configInfo, configAdvanceInfo);
        
        //expect update config tags
        Mockito.verify(jdbcTemplate, times(1)).update(eq(
                        externalConfigInfoPersistService.mapperManager.findMapper(dataSourceService.getDataSourceType(),
                                        TableConstant.CONFIG_TAGS_RELATION)
                                .insert(Arrays.asList("id", "tag_name", "tag_type", "data_id", "group_id", "tenant_id"))),
                eq(configInfoWrapperOld.getId()), eq("tag1"), eq(StringUtils.EMPTY), eq(dataId), eq(group), eq(tenant));
        Mockito.verify(jdbcTemplate, times(1)).update(eq(
                        externalConfigInfoPersistService.mapperManager.findMapper(dataSourceService.getDataSourceType(),
                                        TableConstant.CONFIG_TAGS_RELATION)
                                .insert(Arrays.asList("id", "tag_name", "tag_type", "data_id", "group_id", "tenant_id"))),
                eq(configInfoWrapperOld.getId()), eq("tag2"), eq(StringUtils.EMPTY), eq(dataId), eq(group), eq(tenant));
        
        //expect insert history info
        Mockito.verify(historyConfigInfoPersistService, times(1))
                .insertConfigHistoryAtomic(eq(configInfoWrapperOld.getId()), any(ConfigInfo.class), eq(srcIp), eq(srcUser),
                        any(Timestamp.class), eq("U"));
        
    }