1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
21 var gcflags
string = os
.Getenv("GO_GCFLAGS")
23 func TestMain(m
*testing
.M
) {
25 if testing
.Short() && os
.Getenv("GO_BUILDER_NAME") == "" {
26 fmt
.Printf("SKIP - short mode and $GO_BUILDER_NAME not set\n")
29 log
.SetFlags(log
.Lshortfile
)
33 // tmpDir is used to cleanup logged commands -- s/tmpDir/$TMPDIR/
36 // prettyPrintf prints lines with tmpDir sanitized.
37 func prettyPrintf(format
string, args
...interface{}) {
38 s
:= fmt
.Sprintf(format
, args
...)
40 s
= strings
.ReplaceAll(s
, tmpDir
, "$TMPDIR")
45 func testMain(m
*testing
.M
) int {
46 // Copy testdata into GOPATH/src/testplugin, along with a go.mod file
47 // declaring the same path.
49 GOPATH
, err
:= os
.MkdirTemp("", "plugin_test")
53 defer os
.RemoveAll(GOPATH
)
56 modRoot
:= filepath
.Join(GOPATH
, "src", "testplugin")
57 altRoot
:= filepath
.Join(GOPATH
, "alt", "src", "testplugin")
58 for srcRoot
, dstRoot
:= range map[string]string{
60 filepath
.Join("altpath", "testdata"): altRoot
,
62 if err
:= overlayDir(dstRoot
, srcRoot
); err
!= nil {
65 prettyPrintf("mkdir -p %s\n", dstRoot
)
66 prettyPrintf("rsync -a %s/ %s\n", srcRoot
, dstRoot
)
68 if err
:= os
.WriteFile(filepath
.Join(dstRoot
, "go.mod"), []byte("module testplugin\n"), 0666); err
!= nil {
71 prettyPrintf("echo 'module testplugin' > %s/go.mod\n", dstRoot
)
74 os
.Setenv("GOPATH", filepath
.Join(GOPATH
, "alt"))
75 if err
:= os
.Chdir(altRoot
); err
!= nil {
78 prettyPrintf("cd %s\n", altRoot
)
80 os
.Setenv("PWD", altRoot
)
81 goCmd(nil, "build", "-buildmode=plugin", "-o", filepath
.Join(modRoot
, "plugin-mismatch.so"), "./plugin-mismatch")
83 os
.Setenv("GOPATH", GOPATH
)
84 if err
:= os
.Chdir(modRoot
); err
!= nil {
87 prettyPrintf("cd %s\n", modRoot
)
89 os
.Setenv("PWD", modRoot
)
91 os
.Setenv("LD_LIBRARY_PATH", modRoot
)
93 goCmd(nil, "build", "-buildmode=plugin", "./plugin1")
94 goCmd(nil, "build", "-buildmode=plugin", "./plugin2")
95 so
, err
:= os
.ReadFile("plugin2.so")
99 if err
:= os
.WriteFile("plugin2-dup.so", so
, 0444); err
!= nil {
102 prettyPrintf("cp plugin2.so plugin2-dup.so\n")
104 goCmd(nil, "build", "-buildmode=plugin", "-o=sub/plugin1.so", "./sub/plugin1")
105 goCmd(nil, "build", "-buildmode=plugin", "-o=unnamed1.so", "./unnamed1/main.go")
106 goCmd(nil, "build", "-buildmode=plugin", "-o=unnamed2.so", "./unnamed2/main.go")
107 goCmd(nil, "build", "-o", "host.exe", "./host")
112 func goCmd(t
*testing
.T
, op
string, args
...string) {
116 run(t
, "go", append([]string{op
, "-gcflags", gcflags
}, args
...)...)
119 // escape converts a string to something suitable for a shell command line.
120 func escape(s
string) string {
121 s
= strings
.Replace(s
, "\\", "\\\\", -1)
122 s
= strings
.Replace(s
, "'", "\\'", -1)
123 // Conservative guess at characters that will force quoting
124 if s
== "" || strings
.ContainsAny(s
, "\\ ;#*&$~?!|[]()<>{}`") {
130 // asCommandLine renders cmd as something that could be copy-and-pasted into a command line
131 func asCommandLine(cwd
string, cmd
*exec
.Cmd
) string {
133 if cmd
.Dir
!= "" && cmd
.Dir
!= cwd
{
134 s
+= "cd" + escape(cmd
.Dir
) + ";"
136 for _
, e
:= range cmd
.Env
{
137 if !strings
.HasPrefix(e
, "PATH=") &&
138 !strings
.HasPrefix(e
, "HOME=") &&
139 !strings
.HasPrefix(e
, "USER=") &&
140 !strings
.HasPrefix(e
, "SHELL=") {
145 // These EVs are relevant to this test.
146 for _
, e
:= range os
.Environ() {
147 if strings
.HasPrefix(e
, "PWD=") ||
148 strings
.HasPrefix(e
, "GOPATH=") ||
149 strings
.HasPrefix(e
, "LD_LIBRARY_PATH=") {
154 for _
, a
:= range cmd
.Args
{
162 func run(t
*testing
.T
, bin
string, args
...string) string {
163 cmd
:= exec
.Command(bin
, args
...)
164 cmdLine
:= asCommandLine(".", cmd
)
165 prettyPrintf("%s\n", cmdLine
)
166 cmd
.Stderr
= new(strings
.Builder
)
167 out
, err
:= cmd
.Output()
170 log
.Panicf("%s: %v\n%s", strings
.Join(cmd
.Args
, " "), err
, cmd
.Stderr
)
173 t
.Fatalf("%s: %v\n%s", strings
.Join(cmd
.Args
, " "), err
, cmd
.Stderr
)
177 return string(bytes
.TrimSpace(out
))
180 func TestDWARFSections(t
*testing
.T
) {
181 // test that DWARF sections are emitted for plugins and programs importing "plugin"
182 goCmd(t
, "run", "./checkdwarf/main.go", "plugin2.so", "plugin2.UnexportedNameReuse")
183 goCmd(t
, "run", "./checkdwarf/main.go", "./host.exe", "main.main")
186 func TestRunHost(t
*testing
.T
) {
190 func TestUniqueTypesAndItabs(t
*testing
.T
) {
191 goCmd(t
, "build", "-buildmode=plugin", "./iface_a")
192 goCmd(t
, "build", "-buildmode=plugin", "./iface_b")
193 goCmd(t
, "build", "-o", "iface.exe", "./iface")
194 run(t
, "./iface.exe")
197 func TestIssue18676(t
*testing
.T
) {
198 // make sure we don't add the same itab twice.
199 // The buggy code hangs forever, so use a timeout to check for that.
200 goCmd(t
, "build", "-buildmode=plugin", "-o", "plugin.so", "./issue18676/plugin.go")
201 goCmd(t
, "build", "-o", "issue18676.exe", "./issue18676/main.go")
203 ctx
, cancel
:= context
.WithTimeout(context
.Background(), 10*time
.Second
)
205 cmd
:= exec
.CommandContext(ctx
, "./issue18676.exe")
206 out
, err
:= cmd
.CombinedOutput()
208 t
.Fatalf("%s: %v\n%s", strings
.Join(cmd
.Args
, " "), err
, out
)
212 func TestIssue19534(t
*testing
.T
) {
213 // Test that we can load a plugin built in a path with non-alpha characters.
214 goCmd(t
, "build", "-buildmode=plugin", "-ldflags='-pluginpath=issue.19534'", "-o", "plugin.so", "./issue19534/plugin.go")
215 goCmd(t
, "build", "-o", "issue19534.exe", "./issue19534/main.go")
216 run(t
, "./issue19534.exe")
219 func TestIssue18584(t
*testing
.T
) {
220 goCmd(t
, "build", "-buildmode=plugin", "-o", "plugin.so", "./issue18584/plugin.go")
221 goCmd(t
, "build", "-o", "issue18584.exe", "./issue18584/main.go")
222 run(t
, "./issue18584.exe")
225 func TestIssue19418(t
*testing
.T
) {
226 goCmd(t
, "build", "-buildmode=plugin", "-ldflags=-X main.Val=linkstr", "-o", "plugin.so", "./issue19418/plugin.go")
227 goCmd(t
, "build", "-o", "issue19418.exe", "./issue19418/main.go")
228 run(t
, "./issue19418.exe")
231 func TestIssue19529(t
*testing
.T
) {
232 goCmd(t
, "build", "-buildmode=plugin", "-o", "plugin.so", "./issue19529/plugin.go")
235 func TestIssue22175(t
*testing
.T
) {
236 goCmd(t
, "build", "-buildmode=plugin", "-o", "issue22175_plugin1.so", "./issue22175/plugin1.go")
237 goCmd(t
, "build", "-buildmode=plugin", "-o", "issue22175_plugin2.so", "./issue22175/plugin2.go")
238 goCmd(t
, "build", "-o", "issue22175.exe", "./issue22175/main.go")
239 run(t
, "./issue22175.exe")
242 func TestIssue22295(t
*testing
.T
) {
243 goCmd(t
, "build", "-buildmode=plugin", "-o", "issue.22295.so", "./issue22295.pkg")
244 goCmd(t
, "build", "-o", "issue22295.exe", "./issue22295.pkg/main.go")
245 run(t
, "./issue22295.exe")
248 func TestIssue24351(t
*testing
.T
) {
249 goCmd(t
, "build", "-buildmode=plugin", "-o", "issue24351.so", "./issue24351/plugin.go")
250 goCmd(t
, "build", "-o", "issue24351.exe", "./issue24351/main.go")
251 run(t
, "./issue24351.exe")
254 func TestIssue25756(t
*testing
.T
) {
255 goCmd(t
, "build", "-buildmode=plugin", "-o", "life.so", "./issue25756/plugin")
256 goCmd(t
, "build", "-o", "issue25756.exe", "./issue25756/main.go")
257 // Fails intermittently, but 20 runs should cause the failure
258 for n
:= 20; n
> 0; n
-- {
259 t
.Run(fmt
.Sprint(n
), func(t
*testing
.T
) {
261 run(t
, "./issue25756.exe")
266 // Test with main using -buildmode=pie with plugin for issue #43228
267 func TestIssue25756pie(t
*testing
.T
) {
268 goCmd(t
, "build", "-buildmode=plugin", "-o", "life.so", "./issue25756/plugin")
269 goCmd(t
, "build", "-buildmode=pie", "-o", "issue25756pie.exe", "./issue25756/main.go")
270 run(t
, "./issue25756pie.exe")
273 func TestMethod(t
*testing
.T
) {
274 // Exported symbol's method must be live.
275 goCmd(t
, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go")
276 goCmd(t
, "build", "-o", "method.exe", "./method/main.go")
277 run(t
, "./method.exe")
280 func TestMethod2(t
*testing
.T
) {
281 goCmd(t
, "build", "-buildmode=plugin", "-o", "method2.so", "./method2/plugin.go")
282 goCmd(t
, "build", "-o", "method2.exe", "./method2/main.go")
283 run(t
, "./method2.exe")
286 func TestIssue44956(t
*testing
.T
) {
287 goCmd(t
, "build", "-buildmode=plugin", "-o", "issue44956p1.so", "./issue44956/plugin1.go")
288 goCmd(t
, "build", "-buildmode=plugin", "-o", "issue44956p2.so", "./issue44956/plugin2.go")
289 goCmd(t
, "build", "-o", "issue44956.exe", "./issue44956/main.go")
290 run(t
, "./issue44956.exe")
293 func TestForkExec(t
*testing
.T
) {
294 // Issue 38824: importing the plugin package causes it hang in forkExec on darwin.
297 goCmd(t
, "build", "-o", "forkexec.exe", "./forkexec/main.go")
300 done
:= make(chan int, 1)
303 for i
:= 0; i
< 100; i
++ {
304 cmd
= exec
.Command("./forkexec.exe", "1")
307 t
.Errorf("running command failed: %v", err
)
315 case <-time
.After(5 * time
.Minute
):
317 t
.Fatalf("subprocess hang")