@Override
    public ConfigOperateResult insertOrUpdate(String srcIp, String srcUser, ConfigInfo configInfo,
            Map<String, Object> configAdvanceInfo) {
        if (Objects.isNull(
                findConfigInfoState(configInfo.getDataId(), configInfo.getGroup(), configInfo.getTenant()))) {
            return addConfigInfo(srcIp, srcUser, configInfo, configAdvanceInfo);
        } else {
            return updateConfigInfo(configInfo, srcIp, srcUser, configAdvanceInfo);
        }
    }
@Test
    void testInsertOrUpdateOfUpdateConfigSuccess() {
        
        Map<String, Object> configAdvanceInfo = new HashMap<>();
        String desc = "testdesc";
        String use = "testuse";
        String effect = "testeffect";
        String type = "testtype";
        String schema = "testschema";
        configAdvanceInfo.put("config_tags", "tag1,tag2");
        configAdvanceInfo.put("desc", desc);
        configAdvanceInfo.put("use", use);
        configAdvanceInfo.put("effect", effect);
        configAdvanceInfo.put("type", type);
        configAdvanceInfo.put("schema", schema);
        
        String dataId = "dataId";
        String group = "group";
        String tenant = "tenant";
        String content = "content132456";
        String appName = "app1233";
        ConfigInfo configInfo = new ConfigInfo(dataId, group, tenant, appName, content);
        String encryptedDataKey = "key34567";
        configInfo.setEncryptedDataKey(encryptedDataKey);
        //mock get config state,first and second is not null
        Mockito.when(
                        databaseOperate.queryOne(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(databaseOperate.queryOne(anyString(), eq(new Object[] {dataId, group, tenant}), eq(CONFIG_INFO_WRAPPER_ROW_MAPPER)))
                .thenReturn(configInfoWrapperOld);
        String srcIp = "srcIp";
        String srcUser = "srcUser";
        embeddedConfigInfoPersistService.insertOrUpdate(srcIp, srcUser, configInfo, configAdvanceInfo);
        
        //expect update config info invoked.
        embeddedStorageContextHolderMockedStatic.verify(() -> EmbeddedStorageContextHolder.addSqlContext(anyString(), eq(content),
                eq(MD5Utils.md5Hex(content, Constants.PERSIST_ENCODE)), eq(srcIp), eq(srcUser), eq(appName), eq(desc),
                eq(use), eq(effect), eq(type), eq(schema), eq(encryptedDataKey), eq(dataId), eq(group), eq(tenant)), times(1));
        
        //expect insert config tags
        embeddedStorageContextHolderMockedStatic.verify(
                () -> EmbeddedStorageContextHolder.addSqlContext(anyString(), anyLong(), eq("tag1"), eq(StringUtils.EMPTY), eq(dataId),
                        eq(group), eq(tenant)), times(1));
        embeddedStorageContextHolderMockedStatic.verify(
                () -> EmbeddedStorageContextHolder.addSqlContext(anyString(), anyLong(), eq("tag2"), eq(StringUtils.EMPTY), eq(dataId),
                        eq(group), eq(tenant)), times(1));
        
        //expect insert history info of U
        Mockito.verify(historyConfigInfoPersistService, times(1))
                .insertConfigHistoryAtomic(eq(configInfoWrapperOld.getId()), any(ConfigInfo.class), eq(srcIp), eq(srcUser),
                        any(Timestamp.class), eq("U"));
        
    }