Kubernetes e2e test and test framework
前言
Kubernetes的成功少不了大量工程师的共同参与,而他们之间如何高效的协作,非常值得我们探究。最近研究和使用了他们的e2e测试和框架,还是挺有启发的。
怎样才是好的e2e测试?
不同的人写出的测试用例千差万别,尤其在用例,可能由开发人员编写的情形下,其情形可想而知。要知道,绝大多数开发人员,可能并没有经历过大量测试用例场景的熏陶。所以如何持续输出高质量的e2e测试用例,确实是一个挑战。不过,Kubernetes社区非常聪明,他们抽象出来了一些共性的东西,来希望大家遵守。比如说
- 拒绝“flaky”测试 - 也就是那些偶尔会失败,但是又非常难定位的问题。
- 错误输出要详细,尤其是做断言时,相关信息要有。不过也不要打印太多无效信息,尤其是在case并未失败的情况。
- make case run in anywhere。这一点很重要,因为你的case是提交到社区,可能在各种环境下,各种时间段内运行。面对着各种cloud provider,各种系统负载情况。所以你的case要尽可能稳定,比如APICall,能异步的,就不要假设是同步; 比如多用retry机制等。
- 测试用例要执行的足够快。超过两分钟,就需要给这种测试打上[SLOW]标签。而有这种标签的测试用例,可以运行的场景就比较有限制了。谁又不希望自己写的用例都被尽可能的执行呢?很有激励性的一条规则。
另外,社区不过定下规则,还开发和维护了一系列的基础设施,来辅助上面规则的落地。我们接下来要讲的e2e框架就是其中之一。
e2e 验收测试
搞过测试的应该都知道,在面对复杂系统测试时,我们通常有多套测试环境,但是测试代码通常只有一份。所以为了能更好的区分测试用例,通常采取打标签的方式来给用例分类。这在Kubernetes的e2e里,这也不例外。
Kubernetes默认将测试用例分为下面几类,需要开发者在实际开发用例时,合适的使用。
- 没标签的,默认测试用例是稳定的,支持并发,且运行足够快的
- [Slow] 执行比较慢的用例.(对于具体的时间阈值,Kubernetes不同的文档表示不一致,此处需要修复)
- [Serial] 不支持并发的测试用例,比如占用太多资源,还比如需要重启Node的
- [Disruptive] 会导致其他测试用例失败或者具有破坏性的测试用例
- [Flaky] 不稳定的用例,且很难修复。使用它要非常慎重,因为常规CI jobs并不会运行这些测试用例
- [Feature:.+] 围绕特定非默认Kubernetes集群功能或者非核心功能的测试用例,方便开发以及专项功能适配
当然除了以上标签,还有个比较重要的标签就是[Conformance], 此标签用于验收Kubernetes集群最小功能集,也就是我们常说的MAT测试。所以如果你有个私有部署的k8s集群,就可以通过这套用例来搞验收。方法也很简单,通过下面几步就可以执行:
# under kubernetes folder, compile test cases and ginkgo tool
make WHAT=test/e2e/e2e.test && make ginkgo
# setup for conformance tests
export KUBECONFIG=/path/to/kubeconfig
export KUBERNETES_CONFORMANCE_TEST=y
export KUBERNETES_PROVIDER=skeleton
# run all conformance tests
go run hack/e2e.go -v --test --test_args="--ginkgo.focus=\[Conformance\]"
注意,kubernetes的测试使用的镜像都放在GCR上了,如果你的集群在国内,且还不带翻墙功能,那可能会发现pod会因为下载不了镜像而启动失败。
Kubernetes e2e test framework
研究Kubernetes的e2e测试框架,然后类比我们以往的经验,个人觉得,下面几点特性还是值得借鉴的:
All e2e compiled into one binary, 单一独立二进制
在对服务端程序进行API测试时,我们经常会针对每个服务都创建一个ginkgo suite来框定测试用例的范围,这样做的好处是用例目标非常清晰,但是随着服务数量的增多,这样的suite会越来越来多。从组织上,看起来就稍显杂乱,而且不利于测试服务的输出。
比如,我们考虑这么一个场景,QA需要对新机房部署,或者私有机房进行服务验证。这时候,就通常需要copy所有代码到指定集群在运行了,非常的不方便,而且也容易造成代码泄露。
kubernetes显然也会有这个需求,所以他们改变写法,将所有的测试用例都编译进一个e2e.test的二进制,这样针对上面场景时,就可以直接使用这个可执行文件来操作,非常的方便。
当然可执行文件的方便少不了外部参数的自由注入,以及整体测试用例的精心标记。否则,测试代码写的不规范,需要频繁的针对特定环境修改,也是拒不方便的。
Each case has a uniqe namespace, 每个case拥有唯一的空间
为每条测试用例创建一个独立的空间,是kubernetes e2e framework的一大精华。每条测试用例独享一个空间,彼此不冲突,从而根本上避免并发困扰,借助ginkgo的CLI来运行,会极大的提高执行效率。
而且这处代码的方式也非常优美,很有借鉴价值:
func NewFramework(baseName string, options FrameworkOptions, client clientset.Interface) *Framework {
f := &Framework{
BaseName: baseName,
AddonResourceConstraints: make(map[string]ResourceConstraint),
Options: options,
ClientSet: client,
}
BeforeEach(f.BeforeEach)
AfterEach(f.AfterEach)
return f
}
利用ginkgo 的BeforeEach的嵌套特定,虽然在Describe下就定义framework的初始化(如下),但是在每个It执行前,上面的BeforeEach才会真正执行,所以并不会有冲突:
var _ = framework.KubeDescribe("GKE local SSD [Feature:GKELocalSSD]", func() {
f := framework.NewDefaultFramework("localssd")
It("should write and read from node local SSD [Feature:GKELocalSSD]", func() {
...
})
})
当然e2e框架还负责case执行完的环境清理,并且是按需灵活配置。比如你希望,case失败保留现场,不删除namespace,那么就可以设置flag 参数 delete-namespace-on-failure为false来实现。
Asynchronous wait,异步等待
几乎所有的Kubernetes操作都是异步的,所以不管是产品代码还是测试用例,都广泛的使用了这个异步等待库:kubernetes/vendor/k8s.io/apimachinery/pkg/util/wait。这个库,实现简单,精悍,非常值得学习。
另外,针对测试的异步验证,其实ginkgo(gomega)本身提供的Eventualy,也是非常好用的。
Suitable logs,打印合适的log
Kubernetes e2e 主要使用两种方式输出log,一个是使用glog库,另一个则是framework.Logf方法。glog本身是golang官方提供的log库,使用比较灵活。但是这里主要推荐的还是Framework.Logf。因为使用此方法的log会输出到GinkgoWriter里面,这样当我们使用ginkgo.RunSpecsWithDefaultAndCustomReporters方法时,log不光输出到控制台,也会保存在junit格式的xml文件里,非常方便在jenkins里展示测试结果。
Clean code, 测试代码也可以很干净,优美
很多时候大家会觉得测试代码比较low,其实却不然。代码无所谓优劣,好坏还是依赖写代码的人。而且我想说,测试代码也是可以,并且应该写的很优美的,不然如何提升逼格?!。
我们从Kubernetes e2e能看到很多好的借鉴,比如:
- 抽取主干方法,以突出测试用例主体
- 采用数据驱动方式书写共性测试用例
- 注释工整,多少适宜
- 不输出低级别log
- 代码行长短适宜
- 方法名定义清晰,可读性强
Kubernetes环境普适性的e2e测试框架
现实中,如果需要围绕k8s工作,你可能需要一套,自己的测试框架。不管是测试各种自定义的controller or watcher,还是测试运行在k8s里运行的私有服务。这套框架都适用于你:
https://github.com/CarlJi/golearn/tree/master/src/carlji.com/experiments/k8s_e2e_mat_framework
逻辑改动很小,只是在原有kubernetes e2e 框架基础上抽取了最小集合。以方便快速使用。
是不是很贴心?
童鞋,点个赞吧(⊙o⊙)?
参考文档
- https://github.com/thtanaka/kubernetes/blob/master/docs/devel/writing-good-e2e-tests.md
- https://github.com/thtanaka/kubernetes/blob/master/docs/devel/e2e-tests.md
Contact me ?
Email: jinsdu@outlook.com
Blog: http://www.cnblogs.com/jinsdu/
Github: https://github.com/CarlJi
Kubernetes e2e test and test framework的更多相关文章
- kubernetes高级之动态准入控制
系列目录 动态准入控制器文档介绍了如何使用标准的,插件式的准入控制器.但是,但是由于以下原因,插件式的准入控制器在一些场景下并不灵活: 它们需要编译到kube-apiserver里 它们仅在apise ...
- kube-scheduler的调度上下文
前一章节了解到了kube-scheduler中的概念,该章节则对调度上下文的源码进行分析 Scheduler Scheduler 是整个 kube-scheduler 的一个 structure,提供 ...
- windows类书的学习心得
原文网址:http://www.blogjava.net/sound/archive/2008/08/21/40499.html 现在的计算机图书发展的可真快,很久没去书店,昨日去了一下,真是感叹万千 ...
- 第24 章 : Kubernetes API 编程利器:Operator 和 Operator Framework
Kubernetes API 编程利器:Operator 和 Operator Framework 本节课程主要分享以下三方面的内容: operator 概述 operator framework 实 ...
- [E2E] Robot Framework introduction
We will use demo project as an example, go though QuickStart repo. Install: First you should have py ...
- Kubernetes系统架构简介
1. 前言 Together we will ensure that Kubernetes is a strong and open container management framework fo ...
- angular 调试 js (分 karms protractor / test e2e unit )
首页订阅 Protractor端到端的AngularJS测试框架教程 2014年01月18日 分类:教程, JavaScript, AngularJS Protractor是一个建立在WebDrive ...
- Kubernetes系统架构简介--转
原文地址:http://www.infoq.com/cn/articles/Kubernetes-system-architecture-introduction?utm_campaign=infoq ...
- 【云计算】Kubernetes、Marathon等框架需要解决什么样的问题?
闲谈Kubernetes 的主要特性和经验分享 Capitalonline全球云主机.全球私有网络,免费试用进行时 » 主要介绍 Kubernetes 的主要特性和一些经验.先从整体上 ...
随机推荐
- vue怎么样创建组件呢??
我知道vue中核心就是组件,但是组件是什么呢?组件有什么用呢?怎么用组件呢?怎么样创建自己的组件呢? 前面两个问题就不说了,这里来说说,后面的两个问题: 1)创建自己的组件 通过vue.extend( ...
- Verilog HDL的程序结构及其描述
这篇博文是写给要入门Verilog HDL及其初学者的,也算是我对Verilog HDL学习的一个总结,主要是Verilog HDL的程序结构及其描述,如果有错,欢迎评论指出. 一.Verilog ...
- Python开发【笔记】:单线程下执行多个定时任务
单线程多定时任务 前言:公司业务需求,实例当中大量需要启动定时器的操作:大家都知道python中的定时器用的是threading.Timer,每当启动一个定时器时,程序内部起了一个线程,定时器触发执行 ...
- 前端十万个为什么(之一):我们为什么需要npm?
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px ".PingFang SC"; color: #454545 } span ...
- 【linux相识相知】磁盘分区及文件系统管理详解
磁盘,提供持久的数据存储,它不像我们的内存,如果突然断电了,在内存中的数据一般都会被丢掉了,内存中的数据在保存的时候,会被写到硬盘里面,磁盘也是一种I/O设备. 我们都知道磁盘分区完成之后,还要进行格 ...
- python2.7 + selenium3.4.3浏览器的选择
大家都知道,selenium2对火狐浏览器兼容性比较好,和谷歌和IE相比,好处是无需安装相应的driver.exe来支持启动浏览器,但是缺点是最高支持火狐47版本. 现在selenium3出来了,是不 ...
- Java IO(一):IO和File
一.IO 大多数的应用程序都要与外部设备进行数据交换,最常见的外部设备包含磁盘和网络.IO就是指应用程序对这些设备的数据输入与输出,Java语言定义了许多类专门负责各种方式的输入.输出,这些类都被放在 ...
- hiernate-session
一.概述 Session 是 Hibernate 向应用程序提供操纵数据的主要接口,它提供了基本的保存.更新.删除和加载 Java 对象的方法. 二.Session 缓存 1.简介 (1)Sessio ...
- Java之IO流概述和File基本操作
IO流图解 IO(in / out)流的分类 流向: 输入流 读取数据 输出流 写出数据 数据类型: 字节流 一个字节占8位, 以一个字节为单位读数据 八大数据类型所占字节数: byte(1), ...
- Docker网络——单host网络
前言 前面总结了Docker基础以及Docker存储相关知识,今天来总结一下Docker单主机网络的相关知识.毋庸置疑,网络绝对是任何系统的核心,他在Docker中也占有重要的作用.同样本文基于Clo ...