回归测试系统、方法和电子设备与流程

文档序号:24345856发布日期:2021-03-19 12:29阅读:119来源:国知局
回归测试系统、方法和电子设备与流程

本发明涉及测试技术领域,尤其是涉及一种回归测试系统、方法和电子设备。



背景技术:

流量回放也即将录制的流量数据在回归测试环境中进行重放,模拟线上用户请求,以达到自动化回归测试的目的。目前,在自动化回归测试中,采用的流量回放大致分为两种:一种方案是使用如tcpcopy、goreplay等http流量录制工具,对来自客户端的http请求进行流量录制,并将录制的流量进行存储,用于后续自动化回归测试;另一种方案是在代码的方法中通过加入拦截代码的方式,对流量进行方法级别的拦截和录制。

然而,针对第一种方法,只能实现http请求流量的录制,对于rpc调用,消息队列的消息消费,以及数据库访问无能为力,流量录制只能精确到http接口级别,无法适应微服务的架构体系;而第二种方法,虽然能够做到对rpc调用,消息队列消费,数据库访问等场景的流量录制,但该方式会需要修改已有的项目代码,且应用接入成本较高。



技术实现要素:

本发明的目的在于提供一种回归测试系统、方法和电子设备,可以对待测试服务的数据进行访问,同时可以实现无代码侵入的录制流量的回放,提升了回归测试中测试流量的真实性。

第一方面,本发明提供一种回归测试系统,包括依次连接的重放引擎、代理服务以及待测试服务,其中:重放引擎,用于接收回放请求,并标记回放请求为流量回放请求,以及将流量回放请求发送至代理服务;代理服务,用于将流量回放请求发送给待测试服务;重放引擎,还用于向代理服务反馈与流量回放请求对应的历史响应信息;历史响应信息为预先录制的、所有服务响应流量回放请求的历史响应信息;所有服务包括待测试服务以及与待测试服务相关的调用服务;代理服务,还用于将历史响应信息发送给待测试服务;待测试服务,用于根据历史响应信息,再次执行流量回放请求,并将再次执行产生的当前响应信息反馈给代理服务;代理服务,还用于将当前响应信息反馈给重放引擎;重放引擎,用于对待测试服务的历史响应信息和当前响应信息进行对比,以实现对待测试服务的测试。

在可选的实施方式中,代理服务,还用于在接收到携带有标记信号的流量回放请求之前,接收流量录制请求,并将流量录制请求发送至待测试服务;待测试服务,还用于响应流量录制请求,并将响应流量录制请求后的流量数据发送至代理服务;代理服务还用于,接收流量数据。

第二方面,本发明提供一种回归测试方法,适用于包括多个服务的服务系统,服务系统包括代理服务;回归测试方法包括:接收回归测试请求;根据回归测试请求,确定待测试服务;对回归测试请求进行标记,并将回归测试请求发送给待测试服务;接收待测试服务反馈的测试响应。

在可选的实施方式中,回归测试请求包括流量回放请求;对回归测试请求进行标记,并将回归测试请求发送给待测试服务的步骤,包括:接收来自请求重放引擎的流量回放请求;流量回放请求包括目标回放流量的待测试服务和回放时间段;对流量回放请求进行标记;基于标记后的流量回放请求调用目标待测试服务,并获取目标待测试服务对应的目标回放流量。

在可选的实施方式中,流量回放请求是引流回归平台发送至请求重放引擎,并由请求重放引擎转发给代理服务的。

在可选的实施方式中,回归测试请求包括流量录制请求;在接收来自请求重放引擎的流量回放请求之前,方法还包括:向代理服务发送流量录制请求,并接收代理服务响应流量录制请求的流量数据;代理服务包括微服务架构、数据存储中间件和消息队列中间件的一种或多种;将流量数据存储至预先建立的流量录制存储结构中。

在可选的实施方式中,预先建立的代理服务包括基于应用性能监控系统生成的流量录制代理skywalkingagent。

在可选的实施方式中,接收来自请求重放引擎的流量回放请求的步骤,包括:针对微服务架构、数据存储中间件和消息队列中间件,通过异步采集的方式接收来自请求重放引擎的流量回放请求。

在可选的实施方式中,方法还包括:将目标回放流量发送至回归测试环境,以便基于目标回放流量进行自动化回归测试。

第三方面,本发明提供一种电子设备,包括处理器和存储器;存储器上存储有计算机程序,计算机程序在被处理器运行时执行如前述实施方式任一项的回归测试方法。

本发明提供的本发明提供的回归测试系统、方法和电子设备,该系统包括依次连接的重放引擎、代理服务以及待测试服务,其中:重放引擎用于接收回放请求,标记回放请求为流量回放请求并发送至代理服务,然后通过代理服务将流量回放请求发送给待测试服务。重放引擎还用于向代理服务反馈与流量回放请求对应的历史响应信息,该历史响应信息为预先录制的、所有服务响应流量回放请求的历史响应信息;所有服务包括待测试服务以及与待测试服务相关的调用服务。代理服务用于将历史响应信息发送给待测试服务,以便待测试服务根据历史响应信息,再次执行流量回放请求,并将再次执行产生的当前响应信息反馈给代理服务。代理服务还用于将当前响应信息反馈给重放引擎,然后由重放引擎对待测试服务的历史响应信息和当前响应信息进行对比,以实现对待测试服务的测试。该系统通过重放引擎、代理服务以及待测试服务进行协同工作,可以在自动化回归测试时将线上真实流量在回归测试环境中进行回放,避免了人工手动测试的繁重工作及手动操作出错的可能性,提升了回归测试的测试效率;并且,通过基于标记后的流量回放请求调用待测试服务(诸如消息队列、数据库等),并获取待测试服务对应的目标回放流量,从而可以对待测试服务的数据进行访问;并且通过代理服务进行录制流量回放,可以实现无代码侵入的录制流量的回放,提升了回归测试中测试流量的真实性。

附图说明

为了更清楚地说明本发明具体实施方式或现有技术中的技术方案,下面将对具体实施方式或现有技术描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图是本发明的一些实施方式,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。

图1为本发明实施例提供的一种回归测试系统的结构示意图;

图2为本发明实施例提供的一种回归测试方法的流程示意图;

图3为本发明实施例提供的一种录制流量的回放方法的流程示意图;

图4为本发明实施例提供的一种流量录制的示意图;

图5为本发明实施例提供的一种流量录制存储结构的示意图;

图6为本发明实施例提供的一种流量回放的示意图;

图7为本发明实施例提供的一种录制流量的回放装置的结构示意图;

图8为本发明实施例提供的一种录制流量的回放插件生成方法的流程图;

图9为本发明实施例提供的一种电子设备的结构示意图。

图标:101-重放引擎;102-代理服务;103-待测试服务。

具体实施方式

为使本发明实施例的目的、技术方案和优点更加清楚,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例是本发明一部分实施例,而不是全部的实施例。通常在此处附图中描述和示出的本发明实施例的组件可以以各种不同的配置来布置和设计。

因此,以下对在附图中提供的本发明的实施例的详细描述并非旨在限制要求保护的本发明的范围,而是仅仅表示本发明的选定实施例。基于本发明中的实施例,本领域普通技术人员在没有作出创造性劳动前提下所获得的所有其他实施例,都属于本发明保护的范围。

应注意到:相似的标号和字母在下面的附图中表示类似项,因此,一旦某一项在一个附图中被定义,则在随后的附图中不需要对其进行进一步定义和解释。

下面结合附图,对本发明的一些实施方式作详细说明。在不冲突的情况下,下述的实施例及实施例中的特征可以相互组合。

为便于理解,首先对本实施例提供的一种回归测试系统进行说明,参见图1所示的一种回归测试系统的结构示意图,该系统主要包括依次连接的重放引擎101、代理服务102以及待测试服务103,其中,各部件的连接方式可以为通信连接。重放引擎101用于接收回放请求,并标记回放请求为流量回放请求,以及将流量回放请求发送至代理服务102。然后通过代理服务102将流量回放请求发送给待测试服务103,需要注意的是,回放请求与流量回放请求为一个请求,只是流量回放请求为做了标记后的回放请求。重放引擎101,还用于向代理服务102反馈与上述流量回放请求对应的历史响应信息,该历史响应信息为预先录制的、所有服务响应上述流量回放请求的历史响应信息,所有服务包括待测试服务103以及与待测试服务103相关的调用服务(诸如微服务架构、数据存储中间件和消息队列中间件的一种或多种)。代理服务102,还用于将历史响应信息发送给待测试服务103,以便待测试服务103根据历史响应信息,再次执行流量回放请求,并将再次执行产生的响应信息反馈给代理服务102,进而通过代理服务102将响应信息反馈给重放引擎101,并由重放引擎101对待测试服务的历史响应信息和当前响应信息进行对比,从而实现对待测试服务103的回归测试。

在一种可能的实施方式中,重放引擎101对比的历史响应信息为待测试服务103的历史响应信息和当前响应信息,对此不做赘述。

在一种可能的实施方式中,代理服务102可以单独设置,也可设置在待测试服务或者其他调用服务中,对此不做赘述。

在一种可能的实施方式中,历史响应信息包括待测试服务对请求作出的响应、其他调用服务对请求作出的响应、其他调用服务和待测试服务之间(或者其他调用服务之间)相互调用产生的响应等,对此不做赘述。

在一种实施方式中,上述代理服务,还用于在接收到携带有标记信号的流量回放请求之前,接收流量录制请求,并将流量录制请求发送至待测试服务,然后通过待测试服务响应流量录制请求,并将响应流量录制请求后的流量数据发送至代理服务,以便将预先录制的真实流量在回归测试环境中进行回放,提升了回归测试时模拟测试流量的真实性。

应当注意的是,本实施例的历史响应信息和当前响应信息均为响应流量回放请求的信息,该流量回放请求为同一个请求,并且在得到当前响应信息时,该流量回放请求也并非是一个新的请求,只是针对待测试服务发送的请求。由于与代理服务连接的服务接口通过为多个,诸如消息队列、数据库等,历史响应信息为针对当前所有的服务接口分别得到的响应信息,当前响应信息为针对当前的一个待测试服务进行响应的信息。并且,由于待测试服务在进行响应时,可能会调用其他服务接口的响应信息,因此在实际应用时,当待测试服务对流量回放请求进行响应时,可以同时由代理服务调用其他服务接口做出的历史响应信息。

本发明实施例提供的回归测试系统,通过重放引擎、代理服务以及待测试服务进行协同工作,可以在自动化回归测试时将线上真实流量在回归测试环境中进行回放,避免了人工手动测试的繁重工作及手动操作出错的可能性,提升了回归测试的测试效率;并且,通过基于标记后的流量回放请求调用待测试服务(诸如消息队列、数据库等),并获取待测试服务对应的目标回放流量,从而可以对待测试服务的数据进行访问;并且通过代理服务进行录制流量回放,可以实现无代码侵入的录制流量的回放,提升了回归测试中测试流量的真实性。

本实施例提供的一种回归测试方法,参见图2所示的一种回归测试方法的流程示意图,该方法适用于包括多个服务的服务系统,多个服务诸如可以包括多个服务器,也可以包括多个服务接口,还可以同时包括若干个服务器和若干个服务接口,可以根据实际情况进行设置。服务系统诸如可以包括代理服务,在本实施例中,代理服务为预先建立的包括基于应用性能监控系统生成的流量录制代理skywalkingagent。该方法主要包括以下步骤s202至步骤s208:

步骤s202,接收回归测试请求。

步骤s204,根据回归测试请求,确定待测试服务。

步骤s206,对回归测试请求进行标记,并将回归测试请求发送给待测试服务。

步骤s208,接收待测试服务反馈的测试响应。

为便于理解,对上述流量回归测试方法进行详细说明,该方法由预先建立的流量录制代理执行,预先建立的流量录制代理可以包括基于应用性能监控系统skywalking生成的流量录制代理skywalkingagent,其中,接收的回归测试请求包括流量回放请求,则对所述回归测试请求进行标记,并将所述回归测试请求发送给所述待测试服务具体可参见图3所示的一种录制流量的回放方法的流程示意图,该方法主要包括以下步骤s302至步骤s306:

步骤s302,接收来自请求重放引擎的流量回放请求。

在一种实施方式中,来自请求重放引擎的流量回放请求为通过请求重放引擎接收来自引流回归平台的流量回放请求,也即,该请求回放数据为在引流回归平台管理界面(portal)上发起的接口重放请求,并发送至请求重放引擎,通过请求重放引擎将该流量回放请求发送至预先建立的流量录制代理,进而由预先建立的流量录制代理接收来自请求重放引擎的流量回放请求。在引流回归平台管理界面上发起接口重放请求时,预先选择流量回放请求包括目标回放流量的服务接口和回放时间段。

步骤s304,对流量回放请求进行标记。

当请求重放引擎重放请求到集成测试环境的服务,该请求会打上重放标记,以便流量录制代理根据重放请求标记对请求进行拦截,从而调用重放引擎接口以便获取目标回放流量。同时,对请求进行标记还可以在回放请求时便于识别。

步骤s306,基于标记后的流量回放请求调用待测试服务,并获取待测试服务对应的目标回放流量。

在一种实施方式中,待测试服务包括微服务架构、数据存储中间件和消息队列中间件的一种或多种的服务接口,微服务架构可以包括诸如dubbo、grpc、springcloudfeign架构,数据库存储中间件可以包括诸如mysqldriver、redis,elasticsearch,消息队列可以包括诸如kafka、rocketmq、rabbitmq。通过待测试服务对微服务架构、数据存储中间件或消息队列中间件进行调用,以便基于预先建立的流量录制代理根据重放请求标记对请求进行拦截,并调用重放引擎接口获取mock响应并返回,从而获取相应的目标回放流量。

上述对录制流量进行回放的方法,首先通过预先建立的流量录制代理接收来自请求重放引擎的流量回放请求,并基于标记后的流量回放请求调用待测试服务(诸如消息队列、数据库等),并获取待测试服务对应的目标回放流量,可以对消息队列、数据库等的服务接口的数据进行访问,并且通过预先建立的流量录制代理进行录制流量回放,可以实现无代码侵入的录制流量的回放,提升了回归测试中测试流量的真实性。

在一种实施方式中,在通过请求重放引擎接收来自引流回归平台的流量回放请求之前,首先对流量进行录制,首先通过预先建立的流量录制代理向待测试服务发送流量录制请求,并接收响应流量录制请求的流量数据;将流量数据存储至预先建立的流量录制存储结构。此外,流量录制也可以采用如图4所示的方式通过预先建立的流量录制代理(也即图中skywalkingagent)进行,预先建立的流量录制存储结构可以参见图5所示的数据结构,该流量数据结构较为灵活,比较适合采用非关系型文档数据库mongodb进行存储。

在一种实施方式中,针对微服务架构、数据存储中间件和消息队列中间件,可以通过异步采集的方式接收来自请求重放引擎的流量回放请求,也即可以分别独立的进行不同待测试服务的数据采集,从而可以避免对待测试服务的服务接口性能造成影响。基于skywalkingagent开发的流量录制代理,请求流量需要支持采样,防止线上请求流量过大造成引流回归后端引擎压力过大。

本实施例还提供了一种流量回放的方法,参见图6所示的一种流量回放的示意图,首先在引流回归平台管理界面(portal)上发起接口重放请求,选择哪些接口,以及重放哪个时间段的录制流量,然后通过请求重放引擎读取对应接口在选择时间段的所有录制的请求流量数据,并响应流量数据,进而通过请求重放引擎重放请求到集成测试环境的服务,该请求会打上重放标记,最后对调用服务进行调用,基于skywalkingagent开发的流量录制代理根据重放请求标记对请求进行拦截,并调用重放引擎接口获取mock响应并返回,或者,对数据库服务进行调用,基于skywalkingagent开发的流量录制代理根据重放请求标记对请求进行拦截,并调用重放引擎接口获取mock响应并返回。

此外,在获取到目标回放流量后。还可以进一步将目标回放流量发送至回归测试环境,以便基于目标回放流量进行自动化回归测试。由于录制流量可以进行反复重放,回归测试中出现的问题,开发可以再次重放相同流量复现问题,便于开发排查问题原因。

针对上述录制流量的回放方法,本发明实施例提供一种录制流量的回放装置,参见图7所示的一种录制流量的回放装置的结构示意图,该装置主要包括以下部分:

请求接收模块702,用于接收来自请求重放引擎的流量回放请求;流量回放请求包括目标回放流量的服务接口和回放时间段;

标记模块704,用于对流量回放请求进行标记;

流量回放模块706,用于基于标记后的流量回放请求调用待测试服务,并获取待测试服务对应的目标回放流量。

本发明实施例提供的录制流量回放装置,通过预先建立的流量录制代理接收来自请求重放引擎的流量回放请求,基于标记后的流量回放请求调用待测试服务(诸如消息队列、数据库等),并获取待测试服务对应的目标回放流量,可以对消息队列、数据库等的服务接口的数据进行访问,并且通过预先建立的流量录制代理进行录制流量回放,可以实现无代码侵入的录制流量的回放,提升了回归测试中测试流量的真实性。

在一种实施方式中,流量回放请求是引流回归平台发送至请求重放引擎,并由请求重放引擎转发给流量录制代理的。

在一种实施方式中,上述装置还包括:流量录制模块,用于向待测试服务发送流量录制请求,并接收待测试服务响应流量录制请求的流量数据;将流量数据存储至预先建立的流量录制存储结构中。

在一种实施方式中,上述预先建立的流量录制代理包括基于应用性能监控系统生成的流量录制代理skywalkingagent。

在一种实施方式中,请求接收模块702,进一步用于通过异步采集的方式接收来自请求重放引擎的流量回放请求。

在一种实施方式中,上述装置还包括,测试接口模块,用于将目标回放流量发送至回归测试环境,以便基于目标回放流量进行自动化回归测试。

本发明实施例所提供的装置,其实现原理及产生的技术效果和前述方法实施例相同,为简要描述,装置实施例部分未提及之处,可参考前述方法实施例中相应内容。

针对上述录制流量的回放方法,本发明实施例提供一种录制流量的回放插件,该插件为基于skywalkingagent进行开发的,利用jvm的javaagent实现启动时代码动态注入,从而实现代码无侵入的流量录制,也即实现了引入本实施例的录制流量的回放插件后,也无需对代码其他组件进行更改以适应该录制流量的回放插件,从而在应用接入后,无需应用的开发做任何代码层面的改动,对于应用开发是无感知的。

该录制流量的回放插件参见图8所示的一种录制流量的回放插件生成方法的流程图,实现原理如下:

jvm开始启动时会解析-javaagent参数,如果存在这个参数,就会执行agent_onload方法读取并解析指定jar包后生成jplisagent对象,然后注册jvmtieventcallbacks.vminit这个事件,也就是虚拟机初始化事件,并设置该事件的回调函数eventhandlervminit。然后在jvm初始化时会调用之前注册的eventhandlervminit事件的回调函数,进入processjavastart这个函数,首先会在注册另一个jvm事件classfileloadhook,然后会真正的执行我们在java代码层面编写的premain方法。当jvm开始装载类字节码文件时,会触发之前注册的classfileloadhook事件的回调方法eventhandlerclassfileloadhook,这个回调函数调用transformclassfile方法,生成新的字节码,被jvm装载,完成了启动时代理的全部流程。

为进一步说明,通过以下代码进行描述:

skywalking插件开发流程:

1.首先在源代码的apm-sdk-plugin目录下建立自己的plugin

2.定义拦截点,plugin是使用bytebuddy做字节码增强,类似于aop,相当于给目标类增加了一个代理,例如:

enhanceclass表示需要拦截的类,这里拦截的是asynchttpserverconnectionlistener,因为fireflyhttpserver接收到的所有请求都会进入这个listener,只需要对这个类做一个代理就可以拿到所有请求的性能数据了。这里除了可以按类名去拦截,还可以按照annotation、前缀等方式去拦截目标类。

3.实现拦截器

实现刚才定义的方法拦截器asynchttpserverconnectionlistenerinterceptor

4.构建插件

运行命令:mvncleanpackage-pagent,dist-dskiptests=true

通过以上代码流程实现的无代码侵入流量录制代理插件,实现了对线上系统流量的录制,并支持采样和异步录制,同时还支持将已经录制并存储的流量在回归测试环境中进行回访,提升了回归测试效率。

本发明实施例提供了一种电子设备,具体的,该电子设备包括处理器和存储装置;存储装置上存储有计算机程序,计算机程序在被所述处理器运行时执行如上所述实施方式的任一项所述的方法。

图9为本发明实施例提供的一种电子设备的结构示意图,该电子设备100包括:处理器90,存储器91,总线92和通信接口93,所述处理器90、通信接口93和存储器91通过总线92连接;处理器90用于执行存储器91中存储的可执行模块,例如计算机程序。

其中,存储器91可能包含高速随机存取存储器(ram,randomaccessmemory),也可能还包括非不稳定的存储器(non-volatilememory),例如至少一个磁盘存储器。通过至少一个通信接口93(可以是有线或者无线)实现该系统网元与至少一个其他网元之间的通信连接,可以使用互联网,广域网,本地网,城域网等。

总线92可以是isa总线、pci总线或eisa总线等。所述总线可以分为地址总线、数据总线、控制总线等。为便于表示,图9中仅用一个双向箭头表示,但并不表示仅有一根总线或一种类型的总线。

其中,存储器91用于存储程序,所述处理器90在接收到执行指令后,执行所述程序,前述本发明实施例任一实施例揭示的流过程定义的装置所执行的方法可以应用于处理器90中,或者由处理器90实现。

处理器90可能是一种集成电路芯片,具有信号的处理能力。在实现过程中,上述方法的各步骤可以通过处理器90中的硬件的集成逻辑电路或者软件形式的指令完成。上述的处理器90可以是通用处理器,包括中央处理器(centralprocessingunit,简称cpu)、网络处理器(networkprocessor,简称np)等;还可以是数字信号处理器(digitalsignalprocessing,简称dsp)、专用集成电路(applicationspecificintegratedcircuit,简称asic)、现成可编程门阵列(field-programmablegatearray,简称fpga)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件。可以实现或者执行本发明实施例中的公开的各方法、步骤及逻辑框图。通用处理器可以是微处理器或者该处理器也可以是任何常规的处理器等。结合本发明实施例所公开的方法的步骤可以直接体现为硬件译码处理器执行完成,或者用译码处理器中的硬件及软件模块组合执行完成。软件模块可以位于随机存储器,闪存、只读存储器,可编程只读存储器或者电可擦写可编程存储器、寄存器等本领域成熟的存储介质中。该存储介质位于存储器91,处理器90读取存储器91中的信息,结合其硬件完成上述方法的步骤。

本发明实施例所提供的回归测试系统、方法和电子设备的计算机程序产品,包括存储了处理器可执行的非易失的程序代码的计算机可读存储介质,计算机可读存储介质上存储有计算机程序,该计算机程序被处理器运行时执行前面方法实施例中所述的方法,具体实现可参见方法实施例,在此不再赘述。

所属领域的技术人员可以清楚地了解到,为描述的方便和简洁,上述描述的系统具体工作过程,可以参考前述实施例中的对应过程,在此不再赘述。

本发明实施例所提供的可读存储介质的计算机程序产品,包括存储了程序代码的计算机可读存储介质,所述程序代码包括的指令可用于执行前面方法实施例中所述的方法,具体实现可参见方法实施例,在此不再赘述。

所述功能如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分或者该技术方案的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,包括若干指令用以使得一台计算机设备(可以是个人计算机,服务器,或者网络设备等)执行本发明各个实施例所述方法的全部或部分步骤。而前述的存储介质包括:u盘、移动硬盘、只读存储器(rom,read-onlymemory)、随机存取存储器(ram,randomaccessmemory)、磁碟或者光盘等各种可以存储程序代码的介质。

最后应说明的是:以上各实施例仅用以说明本发明的技术方案,而非对其限制;尽管参照前述各实施例对本发明进行了详细的说明,本领域的普通技术人员应当理解:其依然可以对前述各实施例所记载的技术方案进行修改,或者对其中部分或者全部技术特征进行等同替换;而这些修改或者替换,并不使相应技术方案的本质脱离本发明各实施例技术方案的范围。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1