pulumi/pkg/resource/deploy/source_query_test.go

907 lines
24 KiB
Go

// Copyright 2016-2018, 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 deploy
import (
"context"
"errors"
"io"
"sync"
"testing"
"github.com/blang/semver"
"github.com/hashicorp/hcl/v2"
"github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers"
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/config"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/result"
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/emptypb"
)
func TestQuerySource_Trivial_Wait(t *testing.T) {
t.Parallel()
// Trivial querySource returns immediately with `Wait()`, even with multiple invocations.
// Success case.
var called1 bool
resmon1 := mockResmon{
CancelF: func() error {
called1 = true
return nil
},
}
qs1, _ := newTestQuerySource(&resmon1, func(*querySource) error {
return nil
})
qs1.forkRun()
err := qs1.Wait()
assert.NoError(t, err)
assert.False(t, called1)
// Can be called twice.
err = qs1.Wait()
assert.NoError(t, err)
// Failure case.
var called2 bool
resmon2 := mockResmon{
CancelF: func() error {
called2 = true
return nil
},
}
qs2, _ := newTestQuerySource(&resmon2, func(*querySource) error {
return errors.New("failed")
})
qs2.forkRun()
err = qs2.Wait()
assert.False(t, result.IsBail(err))
assert.Error(t, err)
assert.False(t, called2)
// Can be called twice.
err = qs2.Wait()
assert.False(t, result.IsBail(err))
assert.Error(t, err)
assert.False(t, called2)
}
func TestQuerySource_Async_Wait(t *testing.T) {
t.Parallel()
// `Wait()` executes asynchronously.
// Success case.
//
// test blocks until querySource signals execution has started
// -> querySource blocks until test acknowledges querySource's signal
// -> test blocks on `Wait()` until querySource completes.
var called1 bool
resmon1 := mockResmon{
CancelF: func() error {
called1 = true
return nil
},
}
qs1Start, qs1StartAck := make(chan interface{}), make(chan interface{})
qs1, _ := newTestQuerySource(&resmon1, func(*querySource) error {
qs1Start <- struct{}{}
<-qs1StartAck
return nil
})
qs1.forkRun()
// Wait until querySource starts, then acknowledge starting.
<-qs1Start
go func() {
qs1StartAck <- struct{}{}
}()
// Wait for querySource to complete.
err := qs1.Wait()
assert.NoError(t, err)
assert.False(t, called1)
err = qs1.Wait()
assert.NoError(t, err)
assert.False(t, called1)
var called2 bool
resmon2 := mockResmon{
CancelF: func() error {
called2 = true
return nil
},
}
// Cancellation case.
//
// test blocks until querySource signals execution has started
// -> querySource blocks until test acknowledges querySource's signal
// -> test blocks on `Wait()` until querySource completes.
qs2Start, qs2StartAck := make(chan interface{}), make(chan interface{})
qs2, cancelQs2 := newTestQuerySource(&resmon2, func(*querySource) error {
qs2Start <- struct{}{}
// Block forever.
<-qs2StartAck
return nil
})
qs2.forkRun()
// Wait until querySource starts, then cancel.
<-qs2Start
go func() {
cancelQs2()
}()
// Wait for querySource to complete.
err = qs2.Wait()
assert.NoError(t, err)
assert.True(t, called2)
err = qs2.Wait()
assert.NoError(t, err)
assert.True(t, called2)
}
func TestQueryResourceMonitor_UnsupportedOperations(t *testing.T) {
t.Parallel()
rm := &queryResmon{}
_, err := rm.ReadResource(context.Background(), nil)
assert.EqualError(t, err, "Query mode does not support reading resources")
_, err = rm.RegisterResource(context.Background(), nil)
assert.EqualError(t, err, "Query mode does not support creating, updating, or deleting resources")
_, err = rm.RegisterResourceOutputs(context.Background(), nil)
assert.EqualError(t, err, "Query mode does not support registering resource operations")
}
func TestQueryResourceMonitor(t *testing.T) {
t.Parallel()
t.Run("newQueryResourceMonitor", func(t *testing.T) {
t.Parallel()
t.Run("bad decrypter", func(t *testing.T) {
t.Parallel()
providerRegErrChan := make(chan error, 1)
expectedErr := errors.New("expected error")
resmon, err := newQueryResourceMonitor(
nil, nil, nil, nil, nil, providerRegErrChan, nil, &EvalRunInfo{
Proj: &workspace.Project{
Name: "expected-project",
},
Target: &Target{
Config: config.Map{
config.MustMakeKey("test", "secret"): config.NewSecureValue("secret-value"),
config.MustMakeKey("test", "regular"): config.NewValue("regular-value"),
},
Decrypter: &decrypterMock{
DecryptValueF: func(
ctx context.Context, ciphertext string,
) (string, error) {
return "", expectedErr
},
},
},
},
)
_ = resmon
assert.ErrorIs(t, err, expectedErr)
})
t.Run("ok", func(t *testing.T) {
t.Parallel()
providerRegErrChan := make(chan error, 1)
resmon, err := newQueryResourceMonitor(
nil, nil, nil, nil, nil, providerRegErrChan, nil, &EvalRunInfo{
Proj: &workspace.Project{
Name: "expected-project",
},
Target: &Target{
Name: tokens.MustParseStackName("expected-name"),
},
},
)
assert.NoError(t, err)
assert.Equal(t, "expected-project", resmon.callInfo.Project)
assert.Equal(t, "expected-name", resmon.callInfo.Stack)
})
})
t.Run("Cancel", func(t *testing.T) {
t.Parallel()
expectedErr := errors.New("expected-error")
done := make(chan error, 1)
done <- expectedErr
rm := &queryResmon{
cancel: make(chan bool),
done: done,
}
assert.ErrorIs(t, rm.Cancel(), expectedErr)
})
t.Run("Invoke", func(t *testing.T) {
t.Parallel()
t.Run("bad provider request", func(t *testing.T) {
t.Parallel()
t.Run("bad version", func(t *testing.T) {
t.Parallel()
rm := &queryResmon{}
_, err := rm.Invoke(context.Background(), &pulumirpc.ResourceInvokeRequest{
Tok: "pkgA:index:func",
Version: "bad-version",
})
assert.ErrorContains(t, err, "No Major.Minor.Patch elements found")
})
t.Run("default provider error", func(t *testing.T) {
t.Parallel()
providerRegChan := make(chan *registerResourceEvent, 1)
requests := make(chan defaultProviderRequest, 1)
rm := &queryResmon{
reg: &providers.Registry{},
defaultProviders: &defaultProviders{
requests: requests,
providerRegChan: providerRegChan,
},
}
wg := &sync.WaitGroup{}
wg.Add(1)
expectedErr := errors.New("expected error")
// Needed so defaultProviders.handleRequest() doesn't hang.
go func() {
req := <-rm.defaultProviders.requests
req.response <- defaultProviderResponse{
err: expectedErr,
}
wg.Done()
}()
_, err := rm.Invoke(context.Background(), &pulumirpc.ResourceInvokeRequest{
Tok: "pkgA:index:func",
Version: "1.0.0",
})
wg.Wait()
assert.ErrorIs(t, err, expectedErr)
})
})
})
}
//
// Test querySource constructor.
//
func newTestQuerySource(mon SourceResourceMonitor,
runLangPlugin func(*querySource) error,
) (*querySource, context.CancelFunc) {
cancel, cancelFunc := context.WithCancel(context.Background())
return &querySource{
mon: mon,
runLangPlugin: runLangPlugin,
langPluginFinChan: make(chan error),
cancel: cancel,
}, cancelFunc
}
//
// Mock resource monitor.
//
type mockResmon struct {
AddressF func() string
CancelF func() error
InvokeF func(ctx context.Context,
req *pulumirpc.ResourceInvokeRequest) (*pulumirpc.InvokeResponse, error)
CallF func(ctx context.Context,
req *pulumirpc.ResourceCallRequest) (*pulumirpc.CallResponse, error)
ReadResourceF func(ctx context.Context,
req *pulumirpc.ReadResourceRequest) (*pulumirpc.ReadResourceResponse, error)
RegisterResourceF func(ctx context.Context,
req *pulumirpc.RegisterResourceRequest) (*pulumirpc.RegisterResourceResponse, error)
RegisterResourceOutputsF func(ctx context.Context,
req *pulumirpc.RegisterResourceOutputsRequest) (*emptypb.Empty, error)
AbortChanF func() <-chan bool
}
var _ SourceResourceMonitor = (*mockResmon)(nil)
func (rm *mockResmon) AbortChan() <-chan bool {
if rm.AbortChanF != nil {
return rm.AbortChanF()
}
panic("not implemented")
}
func (rm *mockResmon) Address() string {
if rm.AddressF != nil {
return rm.AddressF()
}
panic("not implemented")
}
func (rm *mockResmon) Cancel() error {
if rm.CancelF != nil {
return rm.CancelF()
}
panic("not implemented")
}
func (rm *mockResmon) Invoke(ctx context.Context,
req *pulumirpc.ResourceInvokeRequest,
) (*pulumirpc.InvokeResponse, error) {
if rm.InvokeF != nil {
return rm.InvokeF(ctx, req)
}
panic("not implemented")
}
func (rm *mockResmon) Call(ctx context.Context,
req *pulumirpc.ResourceCallRequest,
) (*pulumirpc.CallResponse, error) {
if rm.CallF != nil {
return rm.CallF(ctx, req)
}
panic("not implemented")
}
func (rm *mockResmon) ReadResource(ctx context.Context,
req *pulumirpc.ReadResourceRequest,
) (*pulumirpc.ReadResourceResponse, error) {
if rm.ReadResourceF != nil {
return rm.ReadResourceF(ctx, req)
}
panic("not implemented")
}
func (rm *mockResmon) RegisterResource(ctx context.Context,
req *pulumirpc.RegisterResourceRequest,
) (*pulumirpc.RegisterResourceResponse, error) {
if rm.RegisterResourceF != nil {
return rm.RegisterResourceF(ctx, req)
}
panic("not implemented")
}
func (rm *mockResmon) RegisterResourceOutputs(ctx context.Context,
req *pulumirpc.RegisterResourceOutputsRequest,
) (*emptypb.Empty, error) {
if rm.RegisterResourceOutputsF != nil {
return rm.RegisterResourceOutputsF(ctx, req)
}
panic("not implemented")
}
func TestQuerySource(t *testing.T) {
t.Parallel()
t.Run("Wait", func(t *testing.T) {
t.Parallel()
var called bool
providerRegErrChan := make(chan error, 1)
expectedErr := errors.New("expected error")
providerRegErrChan <- expectedErr
src := &querySource{
providerRegErrChan: providerRegErrChan,
// Required to not nil ptr dereference.
cancel: context.Background(),
mon: &mockResmon{
CancelF: func() error {
called = true
return nil
},
},
}
err := src.Wait()
assert.ErrorIs(t, err, expectedErr)
assert.True(t, called)
})
}
func TestRunLangPlugin(t *testing.T) {
t.Parallel()
t.Run("failed to launch language host", func(t *testing.T) {
t.Parallel()
assert.ErrorContains(t, runLangPlugin(&querySource{
plugctx: &plugin.Context{
Host: &mockHost{
LanguageRuntimeF: func(runtime string, info plugin.ProgramInfo) (plugin.LanguageRuntime, error) {
return nil, errors.New("expected error")
},
},
},
runinfo: &EvalRunInfo{
ProjectRoot: "/",
Pwd: "/",
Program: ".",
Proj: &workspace.Project{
Runtime: workspace.NewProjectRuntimeInfo("stuff", map[string]interface{}{}),
},
},
}), "failed to launch language host")
})
t.Run("bad decrypter", func(t *testing.T) {
t.Parallel()
expectedErr := errors.New("expected error")
err := runLangPlugin(&querySource{
plugctx: &plugin.Context{
Host: &mockHost{
LanguageRuntimeF: func(runtime string, info plugin.ProgramInfo) (plugin.LanguageRuntime, error) {
return &mockLanguageRuntime{}, nil
},
},
},
runinfo: &EvalRunInfo{
ProjectRoot: "/",
Pwd: "/",
Program: ".",
Proj: &workspace.Project{
Runtime: workspace.NewProjectRuntimeInfo("stuff", map[string]interface{}{}),
},
Target: &Target{
Config: config.Map{
config.MustMakeKey("test", "secret"): config.NewSecureValue("secret-value"),
config.MustMakeKey("test", "regular"): config.NewValue("regular-value"),
},
Decrypter: &decrypterMock{
DecryptValueF: func(
ctx context.Context, ciphertext string,
) (string, error) {
return "", expectedErr
},
},
},
},
})
assert.ErrorIs(t, err, expectedErr)
})
t.Run("bail successfully", func(t *testing.T) {
t.Parallel()
err := runLangPlugin(&querySource{
plugctx: &plugin.Context{
Host: &mockHost{
LanguageRuntimeF: func(runtime string, info plugin.ProgramInfo) (plugin.LanguageRuntime, error) {
return &mockLanguageRuntime{
RunF: func(info plugin.RunInfo) (string, bool, error) {
return "bail should override progerr", true /* bail */, nil
},
}, nil
},
},
},
// Prevent nilptr dereference.
mon: &mockResmon{
AddressF: func() string { return "" },
},
runinfo: &EvalRunInfo{
ProjectRoot: "/",
Pwd: "/",
Program: ".",
Proj: &workspace.Project{
Runtime: workspace.NewProjectRuntimeInfo("stuff", map[string]interface{}{}),
},
},
})
assert.ErrorContains(t, err, "run bailed")
})
t.Run("progerr", func(t *testing.T) {
t.Parallel()
err := runLangPlugin(&querySource{
plugctx: &plugin.Context{
Host: &mockHost{
LanguageRuntimeF: func(runtime string, info plugin.ProgramInfo) (plugin.LanguageRuntime, error) {
return &mockLanguageRuntime{
RunF: func(info plugin.RunInfo) (string, bool, error) {
return "expected progerr", false /* bail */, nil
},
}, nil
},
},
},
// Prevent nilptr dereference.
mon: &mockResmon{
AddressF: func() string { return "" },
},
runinfo: &EvalRunInfo{
ProjectRoot: "/",
Pwd: "/",
Program: ".",
Proj: &workspace.Project{
Runtime: workspace.NewProjectRuntimeInfo("stuff", map[string]interface{}{}),
},
},
})
assert.ErrorContains(t, err, "expected progerr")
})
t.Run("langhost is run correctly", func(t *testing.T) {
t.Parallel()
var runCalled bool
err := runLangPlugin(&querySource{
plugctx: &plugin.Context{
Host: &mockHost{
LanguageRuntimeF: func(runtime string, p plugin.ProgramInfo) (plugin.LanguageRuntime, error) {
return &mockLanguageRuntime{
RunF: func(info plugin.RunInfo) (string, bool, error) {
runCalled = true
assert.Equal(t, "expected-address", info.MonitorAddress)
assert.Equal(t, "expected-stack", info.Stack)
assert.Equal(t, "expected-project", info.Project)
assert.Equal(t, "/expected-pwd", info.Pwd)
assert.Equal(t, "/expected-pwd", info.Info.ProgramDirectory())
assert.Equal(t, "expected-program", info.Info.EntryPoint())
assert.Equal(t, []string{"expected", "args"}, info.Args)
assert.Equal(t, "secret-value", info.Config[config.MustMakeKey("test", "secret")])
assert.Equal(t, "regular-value", info.Config[config.MustMakeKey("test", "regular")])
assert.True(t, info.QueryMode)
assert.True(t, info.DryRun)
// Disregard Parallel argument.
assert.Equal(t, "expected-organization", info.Organization)
return "", false, nil
},
}, nil
},
},
},
// Prevent nilptr dereference.
mon: &mockResmon{
AddressF: func() string { return "expected-address" },
},
runinfo: &EvalRunInfo{
ProjectRoot: "/",
Proj: &workspace.Project{
Name: "expected-project",
Runtime: workspace.NewProjectRuntimeInfo("stuff", map[string]interface{}{}),
},
Pwd: "/expected-pwd",
Program: "expected-program",
Args: []string{"expected", "args"},
Target: &Target{
Config: config.Map{
config.MustMakeKey("test", "secret"): config.NewSecureValue("secret-value"),
config.MustMakeKey("test", "regular"): config.NewValue("regular-value"),
},
Name: tokens.MustParseStackName("expected-stack"),
Organization: "expected-organization",
Decrypter: &decrypterMock{
DecryptValueF: func(
ctx context.Context, ciphertext string,
) (string, error) {
return ciphertext, nil
},
},
},
},
})
assert.NoError(t, err)
assert.True(t, runCalled)
})
}
type mockHost struct {
ServerAddrF func() string
LogF func(sev diag.Severity, urn resource.URN, msg string, streamID int32)
LogStatusF func(sev diag.Severity, urn resource.URN, msg string, streamID int32)
AnalyzerF func(nm tokens.QName) (plugin.Analyzer, error)
PolicyAnalyzerF func(name tokens.QName, path string, opts *plugin.PolicyAnalyzerOptions) (plugin.Analyzer, error)
ListAnalyzersF func() []plugin.Analyzer
ProviderF func(descriptor workspace.PackageDescriptor) (plugin.Provider, error)
CloseProviderF func(provider plugin.Provider) error
LanguageRuntimeF func(language string, info plugin.ProgramInfo) (plugin.LanguageRuntime, error)
EnsurePluginsF func(plugins []workspace.PluginSpec, kinds plugin.Flags) error
ResolvePluginF func(kind apitype.PluginKind, name string, version *semver.Version) (*workspace.PluginInfo, error)
GetProjectPluginsF func() []workspace.ProjectPlugin
SignalCancellationF func() error
CloseF func() error
}
var _ plugin.Host = (*mockHost)(nil)
func (h *mockHost) ServerAddr() string {
if h.ServerAddrF != nil {
return h.ServerAddrF()
}
panic("unimplemented")
}
func (h *mockHost) Log(sev diag.Severity, urn resource.URN, msg string, streamID int32) {
if h.LogF != nil {
h.LogF(sev, urn, msg, streamID)
return
}
panic("unimplemented")
}
func (h *mockHost) LogStatus(sev diag.Severity, urn resource.URN, msg string, streamID int32) {
if h.LogStatusF != nil {
h.LogStatusF(sev, urn, msg, streamID)
return
}
panic("unimplemented")
}
func (h *mockHost) Analyzer(nm tokens.QName) (plugin.Analyzer, error) {
if h.AnalyzerF != nil {
return h.Analyzer(nm)
}
panic("unimplemented")
}
func (h *mockHost) PolicyAnalyzer(
name tokens.QName, path string, opts *plugin.PolicyAnalyzerOptions,
) (plugin.Analyzer, error) {
if h.PolicyAnalyzerF != nil {
return h.PolicyAnalyzerF(name, path, opts)
}
panic("unimplemented")
}
func (h *mockHost) ListAnalyzers() []plugin.Analyzer {
if h.ListAnalyzersF != nil {
return h.ListAnalyzersF()
}
panic("unimplemented")
}
func (h *mockHost) Provider(descriptor workspace.PackageDescriptor) (plugin.Provider, error) {
if h.ProviderF != nil {
return h.ProviderF(descriptor)
}
panic("unimplemented")
}
func (h *mockHost) CloseProvider(provider plugin.Provider) error {
if h.CloseProviderF != nil {
return h.CloseProviderF(provider)
}
panic("unimplemented")
}
func (h *mockHost) LanguageRuntime(runtime string, info plugin.ProgramInfo) (plugin.LanguageRuntime, error) {
if h.LanguageRuntimeF != nil {
return h.LanguageRuntimeF(runtime, info)
}
panic("unimplemented")
}
func (h *mockHost) EnsurePlugins(plugins []workspace.PluginSpec, kinds plugin.Flags) error {
if h.EnsurePluginsF != nil {
return h.EnsurePluginsF(plugins, kinds)
}
panic("unimplemented")
}
func (h *mockHost) ResolvePlugin(
kind apitype.PluginKind, name string, version *semver.Version,
) (*workspace.PluginInfo, error) {
if h.ResolvePluginF != nil {
return h.ResolvePluginF(kind, name, version)
}
panic("unimplemented")
}
func (h *mockHost) GetProjectPlugins() []workspace.ProjectPlugin {
if h.GetProjectPluginsF != nil {
return h.GetProjectPluginsF()
}
panic("unimplemented")
}
func (h *mockHost) SignalCancellation() error {
if h.SignalCancellationF != nil {
return h.SignalCancellationF()
}
panic("unimplemented")
}
// Close reclaims any resources associated with the host.
func (h *mockHost) Close() error {
if h.CloseF != nil {
return h.CloseF()
}
panic("unimplemented")
}
func (h *mockHost) StartDebugging(plugin.DebuggingInfo) error {
panic("unimplemented")
}
type mockLanguageRuntime struct {
CloseF func() error
GetRequiredPluginsF func(info plugin.ProgramInfo) ([]workspace.PluginSpec, error)
RunF func(info plugin.RunInfo) (string, bool, error)
GetPluginInfoF func() (workspace.PluginInfo, error)
InstallDependenciesF func(options plugin.InstallDependenciesRequest) error
RuntimeOptionsPromptsF func(info plugin.ProgramInfo) ([]plugin.RuntimeOptionPrompt, error)
AboutF func(info plugin.ProgramInfo) (plugin.AboutInfo, error)
GetProgramDependenciesF func(
info plugin.ProgramInfo, transitiveDependencies bool,
) ([]plugin.DependencyInfo, error)
RunPluginF func(
info plugin.RunPluginInfo,
) (io.Reader, io.Reader, context.CancelFunc, error)
GenerateProjectF func(
sourceDirectory, targetDirectory, project string,
strict bool, loaderTarget string, localDependencies map[string]string,
) (hcl.Diagnostics, error)
GeneratePackageF func(
directory string, schema string,
extraFiles map[string][]byte, loaderTarget string, localDependencies map[string]string,
local bool,
) (hcl.Diagnostics, error)
GenerateProgramF func(
program map[string]string,
loaderTarget string,
) (map[string][]byte, hcl.Diagnostics, error)
PackF func(
packageDirectory string,
destinationDirectory string,
) (string, error)
}
var _ plugin.LanguageRuntime = (*mockLanguageRuntime)(nil)
func (rt *mockLanguageRuntime) Close() error {
if rt.CloseF != nil {
return rt.CloseF()
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) GetRequiredPlugins(info plugin.ProgramInfo) ([]workspace.PluginSpec, error) {
if rt.GetRequiredPluginsF != nil {
return rt.GetRequiredPluginsF(info)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) Run(info plugin.RunInfo) (string, bool, error) {
if rt.RunF != nil {
return rt.RunF(info)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) GetPluginInfo() (workspace.PluginInfo, error) {
if rt.GetPluginInfoF != nil {
return rt.GetPluginInfoF()
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) InstallDependencies(request plugin.InstallDependenciesRequest) error {
if rt.InstallDependenciesF != nil {
return rt.InstallDependenciesF(request)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) RuntimeOptionsPrompts(info plugin.ProgramInfo) ([]plugin.RuntimeOptionPrompt, error) {
if rt.RuntimeOptionsPromptsF != nil {
return rt.RuntimeOptionsPromptsF(info)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) About(info plugin.ProgramInfo) (plugin.AboutInfo, error) {
if rt.AboutF != nil {
return rt.AboutF(info)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) GetProgramDependencies(
info plugin.ProgramInfo, transitiveDependencies bool,
) ([]plugin.DependencyInfo, error) {
if rt.GetProgramDependenciesF != nil {
return rt.GetProgramDependenciesF(info, transitiveDependencies)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) RunPlugin(
info plugin.RunPluginInfo,
) (io.Reader, io.Reader, context.CancelFunc, error) {
if rt.RunPluginF != nil {
return rt.RunPluginF(info)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) GenerateProject(
sourceDirectory, targetDirectory, project string,
strict bool, loaderTarget string, localDependencies map[string]string,
) (hcl.Diagnostics, error) {
if rt.GenerateProjectF != nil {
return rt.GenerateProjectF(
sourceDirectory, targetDirectory, project, strict, loaderTarget, localDependencies)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) GeneratePackage(
directory string, schema string, extraFiles map[string][]byte,
loaderTarget string, localDependencies map[string]string,
local bool,
) (hcl.Diagnostics, error) {
if rt.GeneratePackageF != nil {
return rt.GeneratePackageF(directory, schema, extraFiles, loaderTarget, localDependencies, local)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) GenerateProgram(
program map[string]string, loaderTarget string, strict bool,
) (map[string][]byte, hcl.Diagnostics, error) {
if rt.GenerateProgramF != nil {
return rt.GenerateProgramF(program, loaderTarget)
}
panic("unimplemented")
}
func (rt *mockLanguageRuntime) Pack(
packageDirectory string, destinationDirectory string,
) (string, error) {
if rt.PackF != nil {
return rt.PackF(packageDirectory, destinationDirectory)
}
panic("unimplemented")
}