plugin_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package plugins
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "io"
  6. "io/ioutil"
  7. "net/http"
  8. "path/filepath"
  9. "runtime"
  10. "sync"
  11. "testing"
  12. "time"
  13. "github.com/docker/docker/pkg/plugins/transport"
  14. "github.com/docker/go-connections/tlsconfig"
  15. "github.com/pkg/errors"
  16. "github.com/stretchr/testify/assert"
  17. )
  18. const (
  19. fruitPlugin = "fruit"
  20. fruitImplements = "apple"
  21. )
  22. // regression test for deadlock in handlers
  23. func TestPluginAddHandler(t *testing.T) {
  24. // make a plugin which is pre-activated
  25. p := &Plugin{activateWait: sync.NewCond(&sync.Mutex{})}
  26. p.Manifest = &Manifest{Implements: []string{"bananas"}}
  27. storage.plugins["qwerty"] = p
  28. testActive(t, p)
  29. Handle("bananas", func(_ string, _ *Client) {})
  30. testActive(t, p)
  31. }
  32. func TestPluginWaitBadPlugin(t *testing.T) {
  33. p := &Plugin{activateWait: sync.NewCond(&sync.Mutex{})}
  34. p.activateErr = errors.New("some junk happened")
  35. testActive(t, p)
  36. }
  37. func testActive(t *testing.T, p *Plugin) {
  38. done := make(chan struct{})
  39. go func() {
  40. p.waitActive()
  41. close(done)
  42. }()
  43. select {
  44. case <-time.After(100 * time.Millisecond):
  45. _, f, l, _ := runtime.Caller(1)
  46. t.Fatalf("%s:%d: deadlock in waitActive", filepath.Base(f), l)
  47. case <-done:
  48. }
  49. }
  50. func TestGet(t *testing.T) {
  51. p := &Plugin{name: fruitPlugin, activateWait: sync.NewCond(&sync.Mutex{})}
  52. p.Manifest = &Manifest{Implements: []string{fruitImplements}}
  53. storage.plugins[fruitPlugin] = p
  54. plugin, err := Get(fruitPlugin, fruitImplements)
  55. if err != nil {
  56. t.Fatal(err)
  57. }
  58. if p.Name() != plugin.Name() {
  59. t.Fatalf("No matching plugin with name %s found", plugin.Name())
  60. }
  61. if plugin.Client() != nil {
  62. t.Fatal("expected nil Client but found one")
  63. }
  64. if !plugin.IsV1() {
  65. t.Fatal("Expected true for V1 plugin")
  66. }
  67. // check negative case where plugin fruit doesn't implement banana
  68. _, err = Get("fruit", "banana")
  69. assert.Equal(t, errors.Cause(err), ErrNotImplements)
  70. // check negative case where plugin vegetable doesn't exist
  71. _, err = Get("vegetable", "potato")
  72. assert.Equal(t, errors.Cause(err), ErrNotFound)
  73. }
  74. func TestPluginWithNoManifest(t *testing.T) {
  75. addr := setupRemotePluginServer()
  76. defer teardownRemotePluginServer()
  77. m := Manifest{[]string{fruitImplements}}
  78. var buf bytes.Buffer
  79. if err := json.NewEncoder(&buf).Encode(m); err != nil {
  80. t.Fatal(err)
  81. }
  82. mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
  83. if r.Method != "POST" {
  84. t.Fatalf("Expected POST, got %s\n", r.Method)
  85. }
  86. header := w.Header()
  87. header.Set("Content-Type", transport.VersionMimetype)
  88. io.Copy(w, &buf)
  89. })
  90. p := &Plugin{
  91. name: fruitPlugin,
  92. activateWait: sync.NewCond(&sync.Mutex{}),
  93. Addr: addr,
  94. TLSConfig: &tlsconfig.Options{InsecureSkipVerify: true},
  95. }
  96. storage.plugins[fruitPlugin] = p
  97. plugin, err := Get(fruitPlugin, fruitImplements)
  98. if err != nil {
  99. t.Fatal(err)
  100. }
  101. if p.Name() != plugin.Name() {
  102. t.Fatalf("No matching plugin with name %s found", plugin.Name())
  103. }
  104. }
  105. func TestGetAll(t *testing.T) {
  106. tmpdir, unregister := Setup(t)
  107. defer unregister()
  108. p := filepath.Join(tmpdir, "example.json")
  109. spec := `{
  110. "Name": "example",
  111. "Addr": "https://example.com/docker/plugin"
  112. }`
  113. if err := ioutil.WriteFile(p, []byte(spec), 0644); err != nil {
  114. t.Fatal(err)
  115. }
  116. r := newLocalRegistry()
  117. plugin, err := r.Plugin("example")
  118. if err != nil {
  119. t.Fatal(err)
  120. }
  121. plugin.Manifest = &Manifest{Implements: []string{"apple"}}
  122. storage.plugins["example"] = plugin
  123. fetchedPlugins, err := GetAll("apple")
  124. if err != nil {
  125. t.Fatal(err)
  126. }
  127. if fetchedPlugins[0].Name() != plugin.Name() {
  128. t.Fatalf("Expected to get plugin with name %s", plugin.Name())
  129. }
  130. }