* Look for exact match when loading plugins Pulumi's current behavior when loading plugins is surprising in that it will attempt to load the "latest" provider binary instead of exactly the version that was requested. Since provider binaries and provider packages are tied together and versioned together, this is going to be problematic if a provider makes a breaking change. Although there are other issues in this area, this commit fixes the arguably bug-like behavior of loading the latest plugin and instead opts to load the plugin that exactly the requested semver range. Today, the engine will never ask for anything other than an exact version match. Since this is a breaking change, this commit also includes an environment variable that allows users to return back to the "old" plugin loading behavior if they are broken. The intention is that this escape hatch can be removed in a future release once we are confident that this change does not break people. * CR feedback * Use SelectCompatiblePlugin for HasPluginGTE check
236 lines
5.1 KiB
Go
236 lines
5.1 KiB
Go
// Copyright 2016-2019, Pulumi Corporation.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package workspace
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/blang/semver"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestPluginSelection_ExactMatch(t *testing.T) {
|
|
v1 := semver.MustParse("0.1.0")
|
|
v2 := semver.MustParse("0.2.0")
|
|
v3 := semver.MustParse("0.3.0")
|
|
candidatePlugins := []PluginInfo{
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v1,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v2,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "notmyplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: AnalyzerPlugin,
|
|
Version: &v3,
|
|
},
|
|
}
|
|
|
|
requested := semver.MustParseRange("0.2.0")
|
|
result, err := SelectCompatiblePlugin(candidatePlugins, ResourcePlugin, "myplugin", requested)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "myplugin", result.Name)
|
|
assert.Equal(t, "0.2.0", result.Version.String())
|
|
}
|
|
|
|
func TestPluginSelection_ExactMatchNotFound(t *testing.T) {
|
|
v1 := semver.MustParse("0.1.0")
|
|
v2 := semver.MustParse("0.2.1")
|
|
v3 := semver.MustParse("0.3.0")
|
|
candidatePlugins := []PluginInfo{
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v1,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v2,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "notmyplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: AnalyzerPlugin,
|
|
Version: &v3,
|
|
},
|
|
}
|
|
|
|
requested := semver.MustParseRange("0.2.0")
|
|
_, err := SelectCompatiblePlugin(candidatePlugins, ResourcePlugin, "myplugin", requested)
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestPluginSelection_PatchVersionSlide(t *testing.T) {
|
|
v1 := semver.MustParse("0.1.0")
|
|
v2 := semver.MustParse("0.2.0")
|
|
v21 := semver.MustParse("0.2.1")
|
|
v3 := semver.MustParse("0.3.0")
|
|
candidatePlugins := []PluginInfo{
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v1,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v2,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v21,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "notmyplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: AnalyzerPlugin,
|
|
Version: &v3,
|
|
},
|
|
}
|
|
|
|
requested := semver.MustParseRange(">=0.2.0 <0.3.0")
|
|
result, err := SelectCompatiblePlugin(candidatePlugins, ResourcePlugin, "myplugin", requested)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "myplugin", result.Name)
|
|
assert.Equal(t, "0.2.1", result.Version.String())
|
|
}
|
|
|
|
func TestPluginSelection_EmptyVersionNoAlternatives(t *testing.T) {
|
|
v1 := semver.MustParse("0.1.0")
|
|
v2 := semver.MustParse("0.2.1")
|
|
v3 := semver.MustParse("0.3.0")
|
|
candidatePlugins := []PluginInfo{
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v1,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v2,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: nil,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "notmyplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: AnalyzerPlugin,
|
|
Version: &v3,
|
|
},
|
|
}
|
|
|
|
requested := semver.MustParseRange("0.2.0")
|
|
result, err := SelectCompatiblePlugin(candidatePlugins, ResourcePlugin, "myplugin", requested)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "myplugin", result.Name)
|
|
assert.Nil(t, result.Version)
|
|
}
|
|
|
|
func TestPluginSelection_EmptyVersionWithAlternatives(t *testing.T) {
|
|
v1 := semver.MustParse("0.1.0")
|
|
v2 := semver.MustParse("0.2.0")
|
|
v3 := semver.MustParse("0.3.0")
|
|
candidatePlugins := []PluginInfo{
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v1,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v2,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: nil,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: nil,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "notmyplugin",
|
|
Kind: ResourcePlugin,
|
|
Version: &v3,
|
|
},
|
|
{
|
|
Name: "myplugin",
|
|
Kind: AnalyzerPlugin,
|
|
Version: &v3,
|
|
},
|
|
}
|
|
|
|
requested := semver.MustParseRange("0.2.0")
|
|
result, err := SelectCompatiblePlugin(candidatePlugins, ResourcePlugin, "myplugin", requested)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "myplugin", result.Name)
|
|
assert.Equal(t, "0.2.0", result.Version.String())
|
|
}
|