在我发现我的程序存在漏洞之后,我就解决了这个问题。但是,现在我正试图找出如何在 Go 测试中“测试 ”泄漏连接?这是我的问题。
我曾尝试更改测试中的请求数量,但没关系。无论我做什么,我测试中的当前 TCP 连接数都保持不变。
func TestLeakingConnections(t *testing.T) {
getter := myhttp.New()
s := newServer(ok)
defer s.Close()
cur := tcps(t)
for i := 0; i < 1000; i++ {
r, _ := getter.GetWithTimeout(s.URL, time.Millisecond*10)
r.Body.Close()
}
for tries := 10; tries >= 0; tries-- {
growth := tcps(t) - cur
if growth > 5 {
t.Error("leaked")
return
}
}
}
// find tcp connections
func tcps(t *testing.T) (conns int) {
lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
if err != nil {
t.Skip("skipping test; error finding or running lsof")
}
for _, ls := range strings.Split(string(lsof), "\n") {
if strings.Contains(ls, "TCP") {
conns++
}
}
return
}
func newServer(f http.HandlerFunc) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(f))
}
func ok(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/xml")
io.WriteString(w, "<xml></xml>")
}
// myhttp package
// ...other code omitted for clarification
func (g *Getter) GetWithTimeout(
url string,
timeout time.Duration,
) (
*http.Response, error,
) {
// this is the leaking part
// moving this out of here will stop leaks
transport := http.Transport{
DialContext: (&net.Dialer{
Timeout: timeout,
}).DialContext,
TLSHandshakeTimeout: timeout,
ResponseHeaderTimeout: timeout,
ExpectContinueTimeout: timeout,
}
client := http.Client{
Timeout: timeout,
Transport: &transport,
}
return client.Get(url)
}
// fixture worker package
// some outside code injects getter into fixture_worker like this:
getter := myhttp.New()
// NewWithTimeout creates a new fetcher with timeout threshold
func NewWithTimeout(
getter myhttp.HTTPGetter,
fetchURL string,
timeout time.Duration,
) *Fetcher {
return &Fetcher{getter, fetchURL, timeout}
}
// Fetch fetches fixture xml
func (f *Fetcher) Fetch() (*parser.FixtureXML, error) {
res, err := f.getter.GetWithTimeout(f.fetchURL, f.timeout)
if err != nil {
if res != nil && res.Body != nil {
res.Body.Close()
}
return nil, errors.Wrap(err, ErrFetch.Error())
}
defer res.Body.Close()
ioutil.ReadAll(res.Body)
return &parser.FixtureXML{}, nil
}
fixture worker lsof 的输出:https://pastebin.com/fDUkpYsE
测试输出:https://pastebin.com/uGpK0czn
测试永远不会泄漏,而 fixture worker 会泄漏。
Fixture worker 使用与测试相同的代码,使用 myhttp 包请求 http 获取。
最佳答案
如果您希望您的测试代表现实,您需要以与测试之外相同的方式使用它。在这种情况下,您没有阅读任何响应,并且传输恰好在防止丢失连接,因为它会尽快丢弃它们,因为它们无法重复使用。
读取响应将使用连接,并使其进入“泄漏”状态。您还需要在所有情况下正确处理错误,并且始终需要 Close() 响应主体。处理 http 响应并确保其关闭的模式非常简单,并且不一定需要测试(请参阅 What could happen if I don't close response.Body in golang?)
resp, err := GetWithTimeout(s.URL)
if err != nil {
t.Fatal(err)
}
ioutil.ReadAll(resp.Body)
resp.Body.Close()
这可以说是有限的用处,因为最常见的错误将由不正确的错误和响应处理引起,而您没有测试它,因为测试首先需要正确地进行。
这里剩下的问题是您的 GetWithTimeout 方法返回一个错误值和一个有效的 http 响应,这与 http 包文档以及大多数用户的期望相矛盾。如果您要插入错误,最好在同一点处理响应以确保正文被关闭和丢弃。
最后,GetWithTimeout 的大部分内容都是多余的,因为不仅每次都创建 Transports 不正确,而且每个请求都创建一个 http.Client 通常是不必要的,因为它们应该被重用并且对同时使用。
关于testing - 如何在 Go 测试中测试泄漏连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45746753/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende