JMeter 组件详解-Configuration 配置元件

Metadata

title: JMeter 组件详解-Configuration 配置元件
date: 2022-12-13 13:20
tags: 
  - 行动阶段/完成
  - 主题场景/工具
  - 笔记空间/KnowladgeSpace/ToolSpace
  - 细化主题/JMeter
  - 细化主题/组件
  - 细化主题/配置
categories:
  - JMeter
keywords:
  - JMeter
  - 组件
  - 配置
description: 配置元素可用于设置默认值和变量,供采样器稍后使用。注意,这些元素在找到它们的范围的开始处处理,即在同一范围内的任何采样器之前处理。

Configuration | 配置元件

配置元素可用于设置默认值和变量,供采样器稍后使用。注意,这些元素在找到它们的范围的开始处处理,即在同一范围内的任何采样器之前处理。

CSV Data Set Config | CSV 数据集配置

CSV数据集配置用于从文件中读取行,并将它们分割为变量。它比__CSVRead()__StringFromFile()函数更容易使用。它非常适合处理大量变量,并且对于使用”随机”和惟一值进行测试也很有用。

就CPU和内存而言,在运行时生成唯一的随机值非常昂贵,所以只需在测试之前创建数据。如果有必要,文件中的”随机”数据可以与运行时参数结合使用,从而在每次运行中创建不同的值集——例如使用串联——这比在运行时生成所有值要便宜得多。

JMeter允许值被引用;这允许值包含分隔符。如果启用了 “allow quoted data“(“允许引用数据”),值可以用双引号括起来。这些都是删除。要在带引号的字段中包含双引号,请使用两个双引号。

JMeter支持用标题行定义列名的CSV文件。要启用此功能,请将 “Variable Names“ “变量名称”字段保留为空。必须提供正确的分隔符。

默认情况下,文件只打开一次,每个线程将使用文件中的不同行。但是,将行传递给线程的顺序取决于它们的执行顺序,这在迭代之间可能会有所不同。在每个测试迭代的开始读取行。在第一次迭代中解析文件名和模式。

有关其他选项,请参阅下面对共享模式的描述。如果希望每个线程都有自己的一组值,那么需要创建一组文件,每个线程一个文件。例如test1.csv, test2.csv,…,testn.csv。使用文件名test${__threadNum}.csv,将”Sharing mode“(“共享模式”)设置为 “Current thread“(“当前线程”)。

界面

Attribute Description Required
Name 树中显示的这个元素的描述性名称。
要读取的文件的名称。相对文件名根据活动测试计划的路径进行解析。对于分布式测试,CSV文件必须存储在服务器主机系统中启动JMeter服务器的正确相对目录中。也支持绝对文件名,但是请注意,它们不太可能在远程模式下工作,除非远程服务器具有相同的目录结构。如果以两种不同的方式引用同一个物理文件——例如csvdata.txt和./csvdata.txt——那么这些文件将被视为不同的文件。如果操作系统不区分大小写,也会单独打开csvData.TXT。
Yes
File Encoding 用于读取文件的编码,如果不是平台默认值的话。 No
Variable Names 变量名列表。名称必须由分隔符分隔。它们可以用双引号引用。JMeter支持CSV标题行:如果变量名字段为空,那么文件的第一行将被读取并解释为列名列表。 No
Use first line as Variable Names 忽略CSV文件的第一行,它只会在变量名不为空时使用,如果变量名为空,第一行必须包含标题。 No
Delimiter 分隔符,用于分割文件中的记录。如果行上的值比变量的值少,那么剩余的变量将不会更新——因此它们将保留以前的值(如果有的话)。 Yes
Allow quoted data? CSV文件是否允许值被引用?如果启用,值可以括在 "-双引号-允许值包含分隔符。 Yes
Recycle on EOF? 文件是否应该在到达EOF时从头重新读取?(默认是true的) Yes
Stop thread on EOF? 如果循环是假的,线程应该停止在EOF ?(默认是假的) Yes
Sharing mode - All threads - (the default) 该文件在所有线程之间共享。
- Current thread group - 对于出现该元素的每个线程组,每个文件都会打开一次
- Current thread - 每个文件为每个线程分别打开
- Identifier - 共享相同标识符的所有线程共享相同的文件。例如,如果您有4个线程组,您可以为两个或多个组使用一个公共id来在它们之间共享文件。或者可以使用线程号在不同线程组中的相同线程号之间共享文件。
Yes

DNS Cache Manager | DNS缓存管理器

DNS缓存管理器元素允许测试应用程序,当用户从不同的IP接收内容时,负载均衡器(CDN等)后面有多个服务器。JMeter默认使用JVM DNS缓存。这就是为什么集群中只有一个服务器接收负载的原因。DNS缓存管理器在每次迭代时分别为每个线程解析名称,并将解析结果保存到其内部DNS缓存中,该缓存独立于JVM和OS的DNS缓存。

静态主机的映射可以用来模拟类似于/etc/hosts文件的内容。这些条目将优先于自定义解析器。如果要使用此映射,必须启用自定义DNS解析器。

界面

DNS缓存管理器设计用于在线程组或测试计划的根目录中使用。不把它作为子元素的特定HTTP采样

DNS缓存管理器只适用于使用HTTPClient4实现的HTTP请求。

参数说明

Attribute Description Required
Name 树中显示的这个元素的描述性名称。 No
Clear cache each Iteration 如果选中,每次新的迭代开始时,每个线程的DNS缓存都会被清除。 No
Use system DNS resolver 系统DNS解析器将被使用。对于正确的工作编辑 $JAVA_HOME/jre/lib/security/java.security 并且添加 networkaddress.cache.ttl=0 N/A
Use custom DNS resolver 将使用自定义DNS解析器(来自dnsjava库)。 N/A
Hostname or IP address 使用的DNS服务器列表。如果为空,则使用网络配置DNS。 No
Add Button 在DNS服务器表中添加一条表项。 N/A
Delete Button 删除当前选择的表项。 N/A
Host and Hostname or IP address 将主机名映射到静态主机条目,该条目将使用自定义DNS解析器进行解析。 No
Add static host Button 在静态主机表中添加一个条目。 N/A
Delete static host Button 删除表中当前选择的静态主机。 N/A

HTTP Authorization Manager | HTTP授权管理器

界面

授权管理器允许您为使用服务器身份验证限制的网页指定一个或多个用户登录。当您使用浏览器访问受限制的页面,并且浏览器显示登录对话框时,您会看到这种类型的身份验证。JMeter在遇到这种类型的页面时传输登录信息。

授权标头可能不会显示在树视图侦听器的”请求”选项卡中。Java实现执行了先发制人的身份验证,但是当JMeter获取授权报头时,它不返回授权报头。HttpComponents (HC 4.5.X)实现自3.2开始默认为先发制人,头部将显示。要禁用此功能,请设置以下值,在这种情况下,身份验证将只在响应质询时执行。

jmeter.properties 文件中 设置 httpclient4.auth.preemptive=false

注意:上述设置仅适用于HttpClient采样器。

当针对URL查找匹配项时,JMeter依次检查每个条目,并在找到第一个匹配项时停止。因此,最特定的url应该出现在列表的最前面,其次是不那么特定的url。重复的url将被忽略。如果你想为不同的线程使用不同的用户名/密码,你可以使用变量。这些可以使用CSV数据集配置元素(例如)来设置。

Attribute Description Required
Name 树中显示的这个元素的描述性名称。 No
Clear auth on each iteration? 用于Kerberos认证。如果勾选此项,将对每一次主线程组循环的迭代进行身份验证,即使它已经在前一次循环中完成了。如果每个主线程组迭代代表一个虚拟用户的行为,这通常是有用的。 Yes
Base URL 匹配一个或多个HTTP请求URL的部分或完整URL。例如,您指定一个Base URL为 “http://localhost/restricted/“,用户名为”jmeter“,密码为”jmeter“。如果您向URL”http://localhost/restricted/ant/myPage.html“发送HTTP请求,授权管理器将发送名为”jmeter”的用户的登录信息。 yES
Username 需要授权的用户名。 Yes
Password 用户的密码。(注意,此数据未加密存储在测试计划中) Yes
Domain 用于NTLM的域。 No
Realm 用于NTLM的领域。 No
Mechanism 执行的认证类型。JMeter可以基于使用的Http采样器执行不同类型的认证: No

HTTP Cache Manager | HTTP 缓存控制器

HTTP缓存管理器用于在其作用域内向HTTP请求添加缓存功能,以模拟浏览器缓存特性。每个虚拟用户线程都有自己的缓存。默认情况下,缓存管理器将使用LRU算法在每个虚拟用户线程的缓存中存储最多5000个条目。使用属性”maxSize”来修改这个值。请注意,这个值增加越多,HTTP缓存管理器消耗的内存就越多,因此一定要相应地调整-Xmx JVM选项。

如果一个样本是成功的(即有响应代码2xx),然后最后修改和Etag(和过期,如果相关)的值为URL保存。在执行下一个示例之前,采样器检查缓存中是否有条目,如果有,则为请求设置if - last - modified和if - none - match条件报头。

此外,如果”使用Cache-Control/Expires头”选项被选中,那么Cache-Control/Expires值将根据当前时间进行检查。如果请求是一个GET请求,并且时间戳在将来,那么采样器将立即返回,而不需要从远程服务器请求URL。这是为了模拟浏览器的行为。注意,如果cache - control报头为”no-cache”,响应将被存储在缓存中,因此将生成一个有条件的GET请求。如果Cache-Control有其他值,则处理”max-age”过期选项来计算条目的生存期,如果缺少则使用过期头,如果也缺少条目将使用RFC 2616章节13.2.4中指定的Last-Modified time和response Date进行缓存。

如果所请求的文档自缓存以来没有更改,那么响应体将为空。同样,如果过期日期在未来。这可能会给断言带来问题。

界面

参数说明

Attribute Description Required
Name 树中显示的这个元素的描述性名称。 No
Clear cache each iteration 如果选择该选项,则在线程开始时清除缓存。 Yes
Use Cache Control/Expires header when processing GET requests 参见上面的描述。 Yes
Max缓存中的元素个数 参见上面的描述。 Yes

Cookie Manager元素有两个功能:

首先,它像网络浏览器一样存储和发送cookie。如果您有一个HTTP请求和响应包含一个cookie, cookie管理器自动存储该cookie,并将使用它为所有未来的请求,以特定的网站。每个JMeter线程都有自己的“cookie存储区域”。因此,如果您正在测试一个使用cookie存储会话信息的网站,那么每个JMeter线程将拥有自己的会话。注意,这样的Cookie不会出现在Cookie Manager的显示中,但是可以使用View Results Tree Listener查看它们。

JMeter检查接收到的cookie对URL是否有效。这意味着不存储跨域cookie。如果您有错误行为或希望使用跨域cookie,定义JMeter属性 “CookieManager.check.cookies=false

接收到的cookie可以存储为JMeter线程变量。要将cookie保存为变量,需要定义属性”CookieManager.save.cookies=true“。此外,cookie名称在存储之前会以“COOKIE_”作为前缀(这可以避免局部变量的意外损坏)。要恢复到原来的行为,需要定义属性”CookieManager.name.prefix=“(一个或多个空格)。如果启用,一个名为TEST的cookie的值可以被引用为${COOKIE_TEST}

其次,您可以手动添加cookie到cookie管理器。但是,如果您这样做,cookie将被所有JMeter线程共享。

注意,这样的cookie创建时的过期时间较远

默认情况下,具有空值的cookie将被忽略。这可以通过设置JMeter属性来改变:CookieManager.delete_null_cookies=false。注意,这也适用于手动定义的cookie -任何这样的cookie在更新时将从显示中删除。还要注意cookie名称必须是唯一的——如果第二个cookie定义为相同的名称,它将替换第一个cookie。

界面

如果在一个采样器的范围内有多个Cookie Manager,目前没有办法指定要使用哪个。另外,存储在一个cookie管理器中的cookie对任何其他管理器都不可用,所以要小心使用多个cookie管理器。

参数说明

Attribute Description Required
Name 树中显示的这个元素的描述性名称。 No
Clear Cookies each Iteration 如果选中该选项,则在每次执行主线程组循环时清除所有服务器定义的cookie。在GUI中定义的cookie不会被清除。 Yes
Cookie Policy 用于管理cookie的cookie策略。"standard"是3.0之后的默认设置,应该在大多数情况下都可以使用。参见Cookie规范和CookieSpec实现[注:"ignoreCookies"等价于省略CookieManager。] Yes
Implementation HC4CookieHandler (HttpClient 4.5。X的API)。从3.0开始默认为HC4CookieHandler。 [注:如果你有一个网站来测试IPv6地址,选择HC4CookieHandler (IPv6兼容)] Yes
User-Defined Cookies 这使您有机会使用将在测试执行期间被所有线程使用的硬编码cookie。 是服务器的主机名(没有http://);端口当前被忽略。 N/A
Add Button 向cookie表中添加一个条目。 N/A
Delete Button 删除当前选择的表项。 N/A
Load Button 加载之前保存的cookie表,并将条目添加到现有的cookie表条目中。 N/A
Save As Button 将当前cookie表保存到一个文件中(不保存从HTTP响应中提取的任何cookie)。 N/A

HTTP Request Defaults | HTTP 请求默认值

这个元素允许你设置HTTP请求控制器使用的默认值。例如,如果您正在使用25个HTTP请求控制器创建一个Test Plan,并且所有的请求都被发送到相同的服务器,您可以添加一个单独的HTTP Request Defaults元素,填充“服务器名称或IP”字段。然后,当您添加25个HTTP请求控制器时,将“服务器名称或IP”字段保留为空 。控制器将从HTTP Request Defaults元素继承这个字段值。

界面

所有端口值都被同等对待;一个没有指定端口的采样器将使用HTTP请求默认端口(如果提供了)。

参数说明

Attibute Description Required
Name 树中显示的这个元素的描述性名称。 No
Server web服务器的域名或IP地址。例如,www.example.com。[不包含http://前缀。 No
Port web服务器正在监听的端口。 No
Connect Timeout 连接超时。等待连接打开的毫秒数。 No
Response Timeout 响应超时。等待响应的毫秒数。 No
Implementation Java, HttpClient4。如果没有指定,默认值取决于JMeter属性JMeter的值。httpsampler,如果失败,则使用Java实现。 No
Protocol HTTP or HTTPS. No
Content encoding 用于请求的编码。 No
Path 资源的路径(例如/servlets/myServlet)。如果资源需要查询字符串参数,在下面的“发送请求参数”部分添加它们。注意,该路径是完整路径的默认值,而不是应用于HTTP请求屏幕上指定的路径的前缀。 No
Send Parameters With the Request 查询字符串将从您提供的参数列表中生成。每个参数都有一个名称和值。查询字符串将以正确的方式生成,取决于你所做的“方法”的选择(即,如果你选择了GET,查询字符串将被附加到URL,如果是POST,那么它将被单独发送)。此外,如果您正在使用多部分表单发送文件,那么查询字符串将使用多部分表单规范创建。 No
Server (proxy) 执行请求的代理服务器的主机名或IP地址。[不包含http://前缀。] No
Port 代理服务器正在监听的端口。不能,除非指定了代理主机名 No
Username 代理服务器的用户名(可选)。 No
Password 代理服务器密码(可选)。(注意,此数据未加密存储在测试计划中) No
Retrieve All Embedded Resources from HTML Files 告诉JMeter解析HTML文件,并对文件中引用的所有图像、Java小程序、JavaScript文件、css等发送HTTP/HTTPS请求。 No
Use concurrent pool 使用并发连接池来获得嵌入式资源。 No
Size 用于获取嵌入式资源的并发连接的池大小。 No
URLs must match: 如果存在,则必须是一个正则表达式,用于匹配找到的任何嵌入式url。因此,如果您只想从http://example.invalid/下载嵌入式资源,请使用表达式:http://example\.invalid/.* No
URLs must not match: 如果存在,则必须是一个正则表达式,用于过滤掉找到的任何嵌入的url。所以,如果你不想从任何来源下载PNG或SVG文件,使用表达式:.*\.(?i: SVG | PNG) No

注:单选按钮只有两种状态-开或关。这使得不可能始终如一地覆盖设置——关闭意味着关闭,还是意味着使用当前的默认值?JMeter使用后者(否则默认值根本不起作用)。因此,如果按钮是关闭的,那么后面的元素可以将其设置为开启,但如果按钮是开启的,后面的元素就不能将其设置为关闭。

HTTP Header Manager | HTTP 头信息管理器

界面

参数说明

Attribute Description Required
Name 树中显示的这个元素的描述性名称。 No
Name (Header) 请求头的名称。您可能想要试验的两个常见请求头是"User-Agent"和"Referer"。 No (You should have at least one, however)
Value 请求头的值 No (You should have at least one, however)
Add Button 向标题表中添加一个条目。 N/A
Delete Button 删除当前选择的表项。 N/A
Load Button 加载先前保存的头表,并将条目添加到现有的头表条目中。 N/A
Save As Button 将当前头表保存到一个文件中。 N/A

Java Request Defaults | java 请求默认值

Java Request Defaults组件允许您为Java测试设置默认值。

界面

JDBC Connection Configuration | JDBC 连接 配置

从提供的JDBC connection设置创建一个数据库连接(由JDBC RequestSampler使用)。连接可以在线程之间选择性地池化。否则,每个线程将获得自己的连接。JDBC Sampler使用连接配置名称来选择适当的连接。已用池为DBCP,请参见BasicDataSource配置参数

界面

Attribute Description Required
Name 树中显示的连接配置的描述性名称。 No
Variable Name for created pool 连接绑定到的变量的名称。可以使用多个连接,每个连接绑定到不同的变量,从而允许JDBC sampler选择适当的连接。 Yes
Max Number of Connections 池中允许的最大连接数。在大多数情况下,设置为0(0)。这意味着每个线程将得到它自己的池,其中有一个连接,即连接不是线程之间共享的。 Yes
Max Wait (ms) 如果在尝试检索连接的过程中超过了超时时间,池将抛出一个错误 Yes
Time Between Eviction Runs (ms) 空闲对象回收器线程运行之间休眠的毫秒数。当非正值时,不会运行空闲的对象驱逐符线程。(默认为60000,1分钟)。看到 Yes
Auto Commit 打开或关闭连接的自动提交。 Yes
Transaction isolation 事务隔离 Yes
Pool Prepared Statements 每个连接池中准备语句的最大数量。“-1”禁用池,“0”表示不限制准备语句池的数量。(默认为“1”) Yes
Preinit Pool 可以立即初始化连接池。如果设置为False(默认值),使用该池的JDBC请求采样器可能会为第一次查询度量更高的响应时间—因为包括了整个池的连接建立时间。 No
Init SQL statements separated by new line 一组SQL语句,在第一次创建物理连接时,这些SQL语句将用于初始化它们。这些语句只执行一次—当配置的连接工厂创建连接时。 No
Test While Idle 测试池的空闲连接 Yes
Soft Min Evictable Idle Time(ms) 在空闲对象回收器有资格回收连接之前,连接在池中空闲的最短时间,附加条件是至少有minIdle连接保留在池中。 默认值为5000(5秒) Yes
Validation Query 一个简单的查询,用于确定数据库是否仍在响应。这默认是jdbc驱动程序的’isValid()’方法,它适用于许多数据库。然而,有些可能需要不同的查询;例如,Oracle类似于“SELECT 1 FROM DUAL”可以使用。 No
Database URL JDBC数据库连接字符串。 Yes
JDBC Driver class 驱动程序类的完全限定名称。(必须在JMeter的类路径-最容易复制.jar文件到JMeter的/lib目录)。 Yes
Username 要连接的用户名。 No
Password 连接的密码。(注意,此数据未加密存储在测试计划中) No
Connection Properties 建立连接时设置的连接属性(例如Oracle的internal_logon=sysdba) No

Some examples for databases and their parameters are given below.

MySQL Driver class com.mysql.jdbc.Driver Database URL jdbc:mysql://host[:port]/dbname PostgreSQL Driver class org.postgresql.Driver Database URL jdbc:postgresql:{dbname} Oracle Driver class oracle.jdbc.OracleDriver Database URL jdbc:oracle:thin:@//host:port/service OR jdbc:oracle:thin:@(description=(address=(host={mc-name})(protocol=tcp)(port={port-no}))(connect_data=(sid={sid}))) Ingress (2006) Driver class ingres.jdbc.IngresDriver Database URL jdbc:ingres://host:port/db[;attr=value] Microsoft SQL Server (MS JDBC driver) Driver class com.microsoft.sqlserver.jdbc.SQLServerDriver Database URL jdbc:sqlserver://host:port;DatabaseName=dbname Apache Derby Driver class org.apache.derby.jdbc.ClientDriver Database URL jdbc:derby://server[:port]/databaseName[;URLAttributes=value[;…]] MariaDB Driver class org.mariadb.jdbc.Driver Database URL jdbc:mariadb://host[:port]/dbname[;URLAttributes=value[;…]] Exasol (see also JDBC driver documentation) Driver class com.exasol.jdbc.EXADriver Database URL jdbc:exa:host[:port][;schema=SCHEMA_NAME][;prop_x=value_x]

Keystore Configuration | 密钥库配置

界面

Login Config Element | 登录配置

界面

TCP Sampler Config | TCP 采样器 配置

TCP采样器配置为TCP采样器提供缺省数据

界面

User Defined Variables | 用户定义变量

User Defined Variables元素允许您定义一组初始变量,就像在Test Plan中一样。

界面

注意,测试计划中的所有UDV元素—无论它们在哪里—都在开始时处理。

参数说明

Attribute Description Required
Name 树中显示的这个元素的描述性名称。
User Defined Variables 变量名称/值对。"Name"列下的字符串是您需要放在${…}构造中方括号内的内容,以便稍后使用变量。整个${…}将被"Value"列中的字符串替换。

Random Variable | 随机变量

随机变量配置元素用于生成随机数字字符串,并将它们存储在变量中以备以后使用。它比使用用户定义变量和__Random()函数更简单。

界面

Attibute Description Required
Name 树中显示的这个元素的描述性名称。 Yes
Variable Name 存储随机字符串的变量的名称。 Yes
Format String 要使用的java.text.DecimalFormat格式字符串。例如,”000”将生成至少3位的数字,或”USER_000“将生成形式为USER_nnn的输出。如果未指定,则默认使用Long.toString()生成数字。 No
Minimum Value 生成的随机数的最小值(长)。 Yes
Maximum Value 生成的随机数的最大值(长)。 Yes
Random Seed 随机数生成器的种子。如果您使用相同的种子值,将Per Thread设置为true,您将为每个Thread获得与每个Random类相同的值。如果没有设置种子,将使用Random的默认构造函数。 No
Per Thread(User)? 如果为False,则线程组中的所有线程共享生成器。如果为True,则每个线程都有自己的随机生成器。 Yes

Counter | 计数器

允许用户创建一个计数器,该计数器可以在线程组的任何位置引用。计数器配置允许用户配置起始点、最大值和增量。计数器将从开始循环到最大,然后重新开始,像这样继续下去,直到测试结束。

界面

Attribute Description Required
Name 树中显示的这个元素的描述性名称。 No
Starting value 计数器的起始值。计数器将在第一次迭代期间等于这个值(默认为0)。 Yes
Increment 在每次迭代之后计数器增加多少(默认为0,表示没有增加)。 No
Maximum value 如果计数器超过最大值,则将其重置为起始值。默认是长。MAX_VALUE No
Format 可选的格式,例如000将格式为001、002等。它被传递给DecimalFormat,因此可以使用任何有效的格式。如果解释格式有问题,就会忽略它。[默认格式是使用Long.toString()生成的] No
Exported Variable Name 这将是计数器值可用的变量名。如果你把它命名为counterA,你可以使用用户定义值中的${counterA}来访问它(默认情况下,它会创建一个空的字符串变量,可以使用${}来访问,但这是非常不鼓励的) No
Track Counter Independently for each User 换句话说,这是一个全局计数器,还是每个用户都有自己的计数器?如果未选中,计数器是全局的(即,用户#1将在第一次迭代中获得值“1”,用户#2将获得值“2”)。如果勾选此项,每个用户都有一个独立的计数器。 No
Reset counter on each Thread Group Iteration 此选项仅在每个用户跟踪计数器时可用,如果选中,计数器将在每次线程组迭代时重置为Start值。当计数器在循环控制器中时,这是很有用的。 No

Simple Config Element | 简单配置元件

简单配置元素允许您在采样器中添加或重写任意值。您可以选择值的名称和值本身。尽管一些喜欢冒险的用户可能会找到这个元素的用途,但它主要是供开发人员在开发新的JMeter组件时作为基本GUI使用的。

界面

参数说明

Name Description Required
Name 树中显示的这个元素的描述性名称。 Yes
Parameter Name 每个参数的名称。这些值是JMeter工作的内部值,通常没有文档记录。只有熟悉代码的人才知道这些值。 Yes
Parameter Value 应用于该参数的值。 Yes