diff --git a/config/src/main/java/com/alibaba/nacos/config/server/controller/HistoryController.java b/config/src/main/java/com/alibaba/nacos/config/server/controller/HistoryController.java index 81ea3984d3..3de11b85ca 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/controller/HistoryController.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/controller/HistoryController.java @@ -21,6 +21,7 @@ import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.config.server.constant.Constants; import com.alibaba.nacos.config.server.model.ConfigHistoryInfo; +import com.alibaba.nacos.config.server.model.ConfigHistoryInfoPair; import com.alibaba.nacos.config.server.model.ConfigInfoWrapper; import com.alibaba.nacos.config.server.paramcheck.ConfigDefaultHttpParamExtractor; import com.alibaba.nacos.core.paramcheck.ExtractorManager; @@ -100,6 +101,25 @@ public ConfigHistoryInfo getConfigHistoryInfo(@RequestParam("dataId") String dat @RequestParam("nid") Long nid) throws AccessException { return historyService.getConfigHistoryInfo(dataId, group, tenant, nid); } + + /** + * Query the detailed configuration history information pair, including the original version and the updated version. notes: + * + * @param nid history_config_info nid + * @param dataId dataId @since 2.0.3 + * @param group groupId @since 2.0.3 + * @param tenant tenantId @since 2.0.3 + * @return history config info + * @since 2.0.3 add {@link Secured}, dataId, groupId and tenant for history config permission check. + */ + @GetMapping(value = "/pair") + @Secured(action = ActionTypes.READ, signType = SignType.CONFIG) + public ConfigHistoryInfoPair getConfigHistoryInfoPair(@RequestParam("dataId") String dataId, + @RequestParam("group") String group, + @RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant, + @RequestParam(value = "nid") Long nid) throws AccessException { + return historyService.getConfigHistoryInfoPair(dataId, group, tenant, nid); + } /** * Query previous config history information. notes: diff --git a/config/src/main/java/com/alibaba/nacos/config/server/enums/OperationType.java b/config/src/main/java/com/alibaba/nacos/config/server/enums/OperationType.java new file mode 100644 index 0000000000..791c41ffdf --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/enums/OperationType.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.enums; + +/** + * Operation type enum. + * + * @author dirtybit + */ +public enum OperationType { + + /** + * Insert. + */ + INSERT("I"), + + /** + * Update. + */ + UPDATE("U"), + + /** + * Delete. + */ + DELETE("D"); + + /** + * operation type value. + */ + private String value; + + OperationType(String value) { + this.value = value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + +} \ No newline at end of file diff --git a/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigHistoryInfoPair.java b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigHistoryInfoPair.java new file mode 100644 index 0000000000..e3c64e2c07 --- /dev/null +++ b/config/src/main/java/com/alibaba/nacos/config/server/model/ConfigHistoryInfoPair.java @@ -0,0 +1,253 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.config.server.model; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Objects; + +/** + * ConfigHistoryInfoPair. + * + * @author dirtybit + */ +public class ConfigHistoryInfoPair implements Serializable { + + private static final long serialVersionUID = -7827521105376245603L; + + @JsonSerialize(using = ToStringSerializer.class) + private long id; + + private long lastId = -1; + + private String dataId; + + private String group; + + private String tenant; + + private String appName; + + private String md5; + + private String content; + + private String updatedMd5; + + private String updatedContent; + + private String srcIp; + + private String srcUser; + + /** + * Operation type, include inserting, updating and deleting. + */ + private String opType; + + private String publishType; + + private String grayName; + + private String extInfo; + + private Timestamp createdTime; + + private Timestamp lastModifiedTime; + + private String encryptedDataKey; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getLastId() { + return lastId; + } + + public void setLastId(long lastId) { + this.lastId = lastId; + } + + public String getDataId() { + return dataId; + } + + public void setDataId(String dataId) { + this.dataId = dataId; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getUpdatedMd5() { + return updatedMd5; + } + + public void setUpdatedMd5(String updatedMd5) { + this.updatedMd5 = updatedMd5; + } + + public String getUpdatedContent() { + return updatedContent; + } + + public void setUpdatedContent(String updatedContent) { + this.updatedContent = updatedContent; + } + + public String getSrcIp() { + return srcIp; + } + + public void setSrcIp(String srcIp) { + this.srcIp = srcIp; + } + + public String getSrcUser() { + return srcUser; + } + + public void setSrcUser(String srcUser) { + this.srcUser = srcUser; + } + + public String getOpType() { + return opType; + } + + public void setOpType(String opType) { + this.opType = opType; + } + + public String getPublishType() { + return publishType; + } + + public void setPublishType(String publishType) { + this.publishType = publishType; + } + + public String getExtInfo() { + return extInfo; + } + + public void setExtInfo(String extInfo) { + this.extInfo = extInfo; + } + + public Timestamp getCreatedTime() { + return new Timestamp(createdTime.getTime()); + } + + public void setCreatedTime(Timestamp createdTime) { + this.createdTime = new Timestamp(createdTime.getTime()); + } + + public Timestamp getLastModifiedTime() { + return new Timestamp(lastModifiedTime.getTime()); + } + + public void setLastModifiedTime(Timestamp lastModifiedTime) { + this.lastModifiedTime = new Timestamp(lastModifiedTime.getTime()); + } + + public String getGrayName() { + return grayName; + } + + public void setGrayName(String grayName) { + this.grayName = grayName; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getMd5() { + return md5; + } + + public void setMd5(String md5) { + this.md5 = md5; + } + + public String getEncryptedDataKey() { + return encryptedDataKey; + } + + public void setEncryptedDataKey(String encryptedDataKey) { + this.encryptedDataKey = encryptedDataKey; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConfigHistoryInfoPair that = (ConfigHistoryInfoPair) o; + return id == that.id && lastId == that.lastId && Objects.equals(dataId, that.dataId) && Objects.equals(group, + that.group) && Objects.equals(tenant, that.tenant) && Objects.equals(appName, that.appName) + && Objects.equals(md5, that.md5) && Objects.equals(content, that.content) && Objects.equals(updatedMd5, + that.updatedMd5) && Objects.equals(updatedContent, that.updatedContent) && Objects.equals(srcIp, + that.srcIp) && Objects.equals(srcUser, that.srcUser) && Objects.equals(opType, that.opType) + && Objects.equals(createdTime, that.createdTime) && Objects.equals(lastModifiedTime, + that.lastModifiedTime) && Objects.equals(encryptedDataKey, that.encryptedDataKey); + } + + @Override + public int hashCode() { + return Objects.hash(id, lastId, dataId, group, tenant, appName, md5, content, updatedMd5, updatedContent, srcIp, + srcUser, opType, createdTime, lastModifiedTime, encryptedDataKey); + } + +} \ No newline at end of file diff --git a/config/src/main/java/com/alibaba/nacos/config/server/service/HistoryService.java b/config/src/main/java/com/alibaba/nacos/config/server/service/HistoryService.java index 801ed7d4c8..e9fd5b7a80 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/service/HistoryService.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/service/HistoryService.java @@ -17,13 +17,19 @@ package com.alibaba.nacos.config.server.service; import com.alibaba.nacos.common.utils.Pair; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.config.server.enums.OperationType; import com.alibaba.nacos.config.server.model.ConfigHistoryInfo; +import com.alibaba.nacos.config.server.model.ConfigHistoryInfoPair; +import com.alibaba.nacos.config.server.model.ConfigInfo; import com.alibaba.nacos.config.server.model.ConfigInfoWrapper; +import com.alibaba.nacos.config.server.service.repository.ConfigInfoGrayPersistService; import com.alibaba.nacos.persistence.model.Page; import com.alibaba.nacos.config.server.service.repository.ConfigInfoPersistService; import com.alibaba.nacos.config.server.service.repository.HistoryConfigInfoPersistService; import com.alibaba.nacos.plugin.auth.exception.AccessException; import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import java.util.List; @@ -41,11 +47,14 @@ public class HistoryService { private final HistoryConfigInfoPersistService historyConfigInfoPersistService; private final ConfigInfoPersistService configInfoPersistService; + + private final ConfigInfoGrayPersistService configInfoGrayPersistService; public HistoryService(HistoryConfigInfoPersistService historyConfigInfoPersistService, - ConfigInfoPersistService configInfoPersistService) { + ConfigInfoPersistService configInfoPersistService, ConfigInfoGrayPersistService configInfoGrayPersistService) { this.historyConfigInfoPersistService = historyConfigInfoPersistService; this.configInfoPersistService = configInfoPersistService; + this.configInfoGrayPersistService = configInfoGrayPersistService; } /** @@ -114,4 +123,64 @@ private void checkHistoryInfoPermission(ConfigHistoryInfo configHistoryInfo, Str throw new AccessException("Please check dataId, group or namespaceId."); } } -} + + /** + * Query the detailed config history info pair, including the original version and the updated version. + */ + public ConfigHistoryInfoPair getConfigHistoryInfoPair(String dataId, String group, String namespaceId, Long nid) + throws AccessException { + ConfigHistoryInfo configHistoryInfo = historyConfigInfoPersistService.detailConfigHistory(nid); + if (Objects.isNull(configHistoryInfo)) { + return null; + } + + // check if history config match the input + checkHistoryInfoPermission(configHistoryInfo, dataId, group, namespaceId); + + // transform + ConfigHistoryInfoPair configHistoryInfoPair = new ConfigHistoryInfoPair(); + BeanUtils.copyProperties(configHistoryInfo, configHistoryInfoPair); + configHistoryInfoPair.setOpType(configHistoryInfoPair.getOpType().trim()); + + if (OperationType.INSERT.getValue().equals(configHistoryInfoPair.getOpType())) { + configHistoryInfoPair.setUpdatedContent(configHistoryInfoPair.getContent()); + configHistoryInfoPair.setUpdatedMd5(configHistoryInfoPair.getMd5()); + configHistoryInfoPair.setContent(StringUtils.EMPTY); + configHistoryInfoPair.setMd5(StringUtils.EMPTY); + } + + if (OperationType.UPDATE.getValue().equals(configHistoryInfoPair.getOpType())) { + ConfigHistoryInfo nextHistoryInfo = historyConfigInfoPersistService.getNextHistoryInfo(dataId, group, + namespaceId, configHistoryInfoPair.getPublishType(), configHistoryInfoPair.getGrayName(), nid); + if (Objects.isNull(nextHistoryInfo)) { + // get the latest config info + ConfigInfo configInfo = StringUtils.isEmpty(configHistoryInfoPair.getGrayName()) + ? configInfoPersistService.findConfigInfo(dataId, group, namespaceId) + : configInfoGrayPersistService.findConfigInfo4Gray(dataId, group, namespaceId, + configHistoryInfoPair.getGrayName()); + configHistoryInfoPair.setUpdatedMd5(configInfo.getMd5()); + configHistoryInfoPair.setUpdatedContent(configInfo.getContent()); + } else { + configHistoryInfoPair.setUpdatedMd5(nextHistoryInfo.getMd5()); + configHistoryInfoPair.setUpdatedContent(nextHistoryInfo.getContent()); + } + } + + if (OperationType.DELETE.getValue().equals(configHistoryInfoPair.getOpType())) { + configHistoryInfoPair.setUpdatedMd5(StringUtils.EMPTY); + configHistoryInfoPair.setUpdatedContent(StringUtils.EMPTY); + } + + // decrypt content + String encryptedDataKey = configHistoryInfoPair.getEncryptedDataKey(); + String originalContent = EncryptionHandler.decryptHandler(dataId, encryptedDataKey, + configHistoryInfoPair.getContent()).getSecond(); + configHistoryInfoPair.setContent(originalContent); + + String updatedContent = EncryptionHandler.decryptHandler(dataId, encryptedDataKey, + configHistoryInfoPair.getUpdatedContent()).getSecond(); + configHistoryInfoPair.setUpdatedContent(updatedContent); + + return configHistoryInfoPair; + } +} \ No newline at end of file diff --git a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/HistoryConfigInfoPersistService.java b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/HistoryConfigInfoPersistService.java index c15f1ce572..1573a2ba25 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/HistoryConfigInfoPersistService.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/HistoryConfigInfoPersistService.java @@ -117,4 +117,18 @@ List findDeletedConfig(final Timestamp startTime, final */ @Deprecated int findConfigHistoryCountByTime(final Timestamp startTime); + + /** + * Get the next history config detail of the history config. + * + * @param dataId data Id + * @param group group + * @param tenant tenant + * @param publishType publish type + * @param grayName gray name + * @param startNid start nid + * @return the next history config detail of the history config + */ + ConfigHistoryInfo getNextHistoryInfo(String dataId, String group, String tenant, String publishType, String grayName, + long startNid); } diff --git a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedHistoryConfigInfoPersistServiceImpl.java b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedHistoryConfigInfoPersistServiceImpl.java index 8a6a40ce1d..aac9549a37 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedHistoryConfigInfoPersistServiceImpl.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/embedded/EmbeddedHistoryConfigInfoPersistServiceImpl.java @@ -210,4 +210,22 @@ public int findConfigHistoryCountByTime(final Timestamp startTime) { } return result; } + + @Override + public ConfigHistoryInfo getNextHistoryInfo(String dataId, String group, String tenant, String publishType, + String grayName, long startNid) { + HistoryConfigInfoMapper historyConfigInfoMapper = mapperManager.findMapper( + dataSourceService.getDataSourceType(), TableConstant.HIS_CONFIG_INFO); + MapperContext context = new MapperContext(); + context.putWhereParameter(FieldConstant.DATA_ID, dataId); + context.putWhereParameter(FieldConstant.GROUP_ID, group); + context.putWhereParameter(FieldConstant.TENANT_ID, tenant); + context.putWhereParameter(FieldConstant.PUBLISH_TYPE, publishType); + context.putWhereParameter(FieldConstant.GRAY_NAME, grayName); + context.putWhereParameter(FieldConstant.NID, startNid); + MapperResult sqlFetchRows = historyConfigInfoMapper.getNextHistoryInfo(context); + return databaseOperate.queryOne(sqlFetchRows.getSql(), sqlFetchRows.getParamList().toArray(), + HISTORY_DETAIL_ROW_MAPPER); + } + } diff --git a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalConfigInfoPersistServiceImpl.java b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalConfigInfoPersistServiceImpl.java index 68970912f7..e6be63d49c 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalConfigInfoPersistServiceImpl.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalConfigInfoPersistServiceImpl.java @@ -177,6 +177,7 @@ public ConfigOperateResult addConfigInfo(final String srcIp, final String srcUse * @param configAdvanceInfo advance info * @return */ + @Override public ConfigOperateResult insertOrUpdate(String srcIp, String srcUser, ConfigInfo configInfo, Map configAdvanceInfo) { try { diff --git a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalHistoryConfigInfoPersistServiceImpl.java b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalHistoryConfigInfoPersistServiceImpl.java index 8669edcf69..a2dde077f3 100644 --- a/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalHistoryConfigInfoPersistServiceImpl.java +++ b/config/src/main/java/com/alibaba/nacos/config/server/service/repository/extrnal/ExternalHistoryConfigInfoPersistServiceImpl.java @@ -241,4 +241,29 @@ public int findConfigHistoryCountByTime(final Timestamp startTime) { } return result; } + + @Override + public ConfigHistoryInfo getNextHistoryInfo(String dataId, String group, String tenant, String publishType, + String grayName, long startNid) { + HistoryConfigInfoMapper historyConfigInfoMapper = mapperManager.findMapper( + dataSourceService.getDataSourceType(), TableConstant.HIS_CONFIG_INFO); + MapperContext context = new MapperContext(); + context.putWhereParameter(FieldConstant.DATA_ID, dataId); + context.putWhereParameter(FieldConstant.GROUP_ID, group); + context.putWhereParameter(FieldConstant.TENANT_ID, tenant); + context.putWhereParameter(FieldConstant.PUBLISH_TYPE, publishType); + context.putWhereParameter(FieldConstant.NID, startNid); + context.putWhereParameter(FieldConstant.GRAY_NAME, grayName); + MapperResult sqlFetchRows = historyConfigInfoMapper.getNextHistoryInfo(context); + try { + ConfigHistoryInfo historyInfo = jt.queryForObject(sqlFetchRows.getSql(), + sqlFetchRows.getParamList().toArray(), HISTORY_DETAIL_ROW_MAPPER); + return historyInfo; + } catch (EmptyResultDataAccessException emptyResultDataAccessException) { + return null; + } catch (DataAccessException e) { + LogUtil.FATAL_LOG.error("[db-error] " + e, e); + throw e; + } + } } diff --git a/config/src/test/java/com/alibaba/nacos/config/server/controller/HistoryControllerTest.java b/config/src/test/java/com/alibaba/nacos/config/server/controller/HistoryControllerTest.java index f36b2ddf66..b0e8e58b79 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/controller/HistoryControllerTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/controller/HistoryControllerTest.java @@ -17,8 +17,10 @@ package com.alibaba.nacos.config.server.controller; import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.config.server.constant.Constants; import com.alibaba.nacos.config.server.model.ConfigHistoryInfo; +import com.alibaba.nacos.config.server.model.ConfigHistoryInfoPair; import com.alibaba.nacos.config.server.model.ConfigInfoWrapper; import com.alibaba.nacos.config.server.service.HistoryService; import com.alibaba.nacos.persistence.model.Page; @@ -188,5 +190,33 @@ void testGetDataIds() throws Exception { assertEquals(configInfoWrapper.getContent(), resConfigInfoWrapper.getContent()); } - + + @Test + void testGetConfigHistoryInfoPair() throws Exception { + + ConfigHistoryInfoPair configHistoryInfoPair = new ConfigHistoryInfoPair(); + configHistoryInfoPair.setDataId("test"); + configHistoryInfoPair.setGroup("test"); + configHistoryInfoPair.setContent("test"); + configHistoryInfoPair.setUpdatedContent("test updated"); + configHistoryInfoPair.setTenant(StringUtils.EMPTY); + configHistoryInfoPair.setCreatedTime(new Timestamp(new Date().getTime())); + configHistoryInfoPair.setLastModifiedTime(new Timestamp(new Date().getTime())); + + when(historyController.getConfigHistoryInfoPair("test", "test", StringUtils.EMPTY, 1L)) + .thenReturn(configHistoryInfoPair); + + MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(Constants.HISTORY_CONTROLLER_PATH + "/pair") + .param("dataId", "test").param("group", "test") + .param("tenant", "").param("nid", "1"); + + String actualValue = mockmvc.perform(builder).andReturn().getResponse().getContentAsString(); + ConfigHistoryInfoPair resConfigHistoryInfoPair = JacksonUtils.toObj(actualValue, ConfigHistoryInfoPair.class); + + assertEquals(configHistoryInfoPair.getDataId(), resConfigHistoryInfoPair.getDataId()); + assertEquals(configHistoryInfoPair.getGroup(), resConfigHistoryInfoPair.getGroup()); + assertEquals(configHistoryInfoPair.getContent(), resConfigHistoryInfoPair.getContent()); + assertEquals(configHistoryInfoPair.getUpdatedContent(), resConfigHistoryInfoPair.getUpdatedContent()); + } + } diff --git a/config/src/test/java/com/alibaba/nacos/config/server/service/HistoryServiceTest.java b/config/src/test/java/com/alibaba/nacos/config/server/service/HistoryServiceTest.java index 0d2b29e8f7..0ebbfdcd50 100644 --- a/config/src/test/java/com/alibaba/nacos/config/server/service/HistoryServiceTest.java +++ b/config/src/test/java/com/alibaba/nacos/config/server/service/HistoryServiceTest.java @@ -16,8 +16,13 @@ package com.alibaba.nacos.config.server.service; +import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.config.server.constant.Constants; +import com.alibaba.nacos.config.server.enums.OperationType; import com.alibaba.nacos.config.server.model.ConfigHistoryInfo; +import com.alibaba.nacos.config.server.model.ConfigHistoryInfoPair; import com.alibaba.nacos.config.server.model.ConfigInfoWrapper; +import com.alibaba.nacos.config.server.service.repository.ConfigInfoGrayPersistService; import com.alibaba.nacos.config.server.service.repository.ConfigInfoPersistService; import com.alibaba.nacos.config.server.service.repository.HistoryConfigInfoPersistService; import com.alibaba.nacos.persistence.model.Page; @@ -54,6 +59,14 @@ class HistoryServiceTest { private static final String TEST_TENANT = ""; private static final String TEST_CONTENT = "test config"; + + private static final String TEST_UPDATED_CONTENT = "test config updated"; + + private static final String TEST_OP_TYPE = OperationType.UPDATE.getValue(); + + private static final String TEST_MD5 = "77963b7a931377ad4ab5ad6a9cd718aa"; + + private static final String TEST_UPDATED_MD5 = "3ba1e44fa18519221f6c70afc0e8ae84"; private HistoryService historyService; @@ -62,10 +75,13 @@ class HistoryServiceTest { @Mock private ConfigInfoPersistService configInfoPersistService; + + @Mock + private ConfigInfoGrayPersistService configInfoGrayPersistService; @BeforeEach void setUp() throws Exception { - this.historyService = new HistoryService(historyConfigInfoPersistService, configInfoPersistService); + this.historyService = new HistoryService(historyConfigInfoPersistService, configInfoPersistService, configInfoGrayPersistService); } @Test @@ -166,4 +182,47 @@ void testGetConfigListByNamespace() { assertEquals(configInfoWrapper.getGroup(), actualConfigInfoWrapper.getGroup()); assertEquals(configInfoWrapper.getContent(), actualConfigInfoWrapper.getContent()); } + + @Test + void testGetConfigHistoryInfoPair() throws Exception { + ConfigHistoryInfo configHistoryInfo = new ConfigHistoryInfo(); + configHistoryInfo.setDataId(TEST_DATA_ID); + configHistoryInfo.setGroup(TEST_GROUP); + configHistoryInfo.setContent(TEST_CONTENT); + configHistoryInfo.setTenant(TEST_TENANT); + configHistoryInfo.setOpType(TEST_OP_TYPE); + configHistoryInfo.setMd5(TEST_MD5); + configHistoryInfo.setPublishType(Constants.FORMAL); + configHistoryInfo.setGrayName(StringUtils.EMPTY); + configHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime())); + configHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime())); + + when(historyConfigInfoPersistService.detailConfigHistory(1L)).thenReturn(configHistoryInfo); + + ConfigHistoryInfo nextHistoryInfo = new ConfigHistoryInfo(); + nextHistoryInfo.setDataId(TEST_DATA_ID); + nextHistoryInfo.setGroup(TEST_GROUP); + nextHistoryInfo.setTenant(TEST_TENANT); + nextHistoryInfo.setOpType(TEST_OP_TYPE); + nextHistoryInfo.setMd5(TEST_UPDATED_MD5); + nextHistoryInfo.setContent(TEST_UPDATED_CONTENT); + nextHistoryInfo.setPublishType(Constants.FORMAL); + nextHistoryInfo.setGrayName(StringUtils.EMPTY); + nextHistoryInfo.setCreatedTime(new Timestamp(new Date().getTime())); + nextHistoryInfo.setLastModifiedTime(new Timestamp(new Date().getTime())); + + when(historyConfigInfoPersistService.getNextHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_TENANT, Constants.FORMAL, + StringUtils.EMPTY, 1L)).thenReturn(nextHistoryInfo); + + ConfigHistoryInfoPair resConfigHistoryInfoPair = historyService.getConfigHistoryInfoPair(TEST_DATA_ID, TEST_GROUP, + TEST_TENANT, 1L); + + verify(historyConfigInfoPersistService).getNextHistoryInfo(TEST_DATA_ID, TEST_GROUP, TEST_TENANT, Constants.FORMAL, + StringUtils.EMPTY, 1L); + + assertEquals(nextHistoryInfo.getDataId(), resConfigHistoryInfoPair.getDataId()); + assertEquals(nextHistoryInfo.getGroup(), resConfigHistoryInfoPair.getGroup()); + assertEquals(nextHistoryInfo.getMd5(), resConfigHistoryInfoPair.getUpdatedMd5()); + assertEquals(nextHistoryInfo.getContent(), resConfigHistoryInfoPair.getUpdatedContent()); + } } diff --git a/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/constants/FieldConstant.java b/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/constants/FieldConstant.java index 7dff366990..db3bdb2d5f 100644 --- a/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/constants/FieldConstant.java +++ b/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/constants/FieldConstant.java @@ -43,6 +43,8 @@ public class FieldConstant { public static final String PAGE_SIZE = "pageSize"; public static final String ID = "id"; + + public static final String NID = "nid"; public static final String START_TIME = "startTime"; diff --git a/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/mapper/HistoryConfigInfoMapper.java b/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/mapper/HistoryConfigInfoMapper.java index c98c89592c..32ddd63716 100644 --- a/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/mapper/HistoryConfigInfoMapper.java +++ b/plugin/datasource/src/main/java/com/alibaba/nacos/plugin/datasource/mapper/HistoryConfigInfoMapper.java @@ -17,12 +17,14 @@ package com.alibaba.nacos.plugin.datasource.mapper; import com.alibaba.nacos.common.utils.CollectionUtils; +import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.plugin.datasource.constants.FieldConstant; import com.alibaba.nacos.plugin.datasource.constants.TableConstant; import com.alibaba.nacos.plugin.datasource.model.MapperContext; import com.alibaba.nacos.plugin.datasource.model.MapperResult; import java.util.Collections; +import java.util.List; /** * The history config info mapper. @@ -121,4 +123,33 @@ default MapperResult detailPreviousConfigHistory(MapperContext context) { default String getTableName() { return TableConstant.HIS_CONFIG_INFO; } + + /** + * Get updated history config detail of the history config. The default sql: SELECT + * nid,data_id,group_id,tenant_id,app_name,content,md5,src_user,src_ip,op_type,gmt_create,gmt_modified FROM + * his_config_info WHERE data_id = ? AND group_id = ? AND tenant_id = ? AND publish_type = ? AND gray_name = ? + * AND nid > ? ORDER BY nid LIMIT 1 + * + * @param context sql paramMap + * @return The sql of getting the next history config detail of the history config. + */ + default MapperResult getNextHistoryInfo(MapperContext context) { + String sql = "SELECT nid,data_id,group_id,tenant_id,app_name,content,md5,src_user,src_ip,op_type,publish_type," + + "gray_name,ext_info,gmt_create,gmt_modified,encrypted_data_key FROM his_config_info " + + "WHERE data_id = ? AND group_id = ? AND tenant_id = ? AND publish_type = ? " + + (StringUtils.isEmpty(context.getContextParameter(FieldConstant.GRAY_NAME)) ? "" : "AND gray_name = ? ") + + "AND nid > ? ORDER BY nid LIMIT 1"; + + List paramList = CollectionUtils.list( + context.getWhereParameter(FieldConstant.DATA_ID), + context.getWhereParameter(FieldConstant.GROUP_ID), + context.getWhereParameter(FieldConstant.TENANT_ID), + context.getWhereParameter(FieldConstant.PUBLISH_TYPE), + context.getWhereParameter(FieldConstant.NID)); + if (!StringUtils.isEmpty(context.getContextParameter(FieldConstant.GRAY_NAME))) { + paramList.add(4, context.getWhereParameter(FieldConstant.GRAY_NAME)); + } + + return new MapperResult(sql, paramList); + } }