Skip to content

Commit

Permalink
refactor test utils
Browse files Browse the repository at this point in the history
  • Loading branch information
EronWright committed Mar 5, 2024
1 parent 3ce28e7 commit a10d723
Show file tree
Hide file tree
Showing 6 changed files with 403 additions and 354 deletions.
126 changes: 126 additions & 0 deletions provider/pkg/host/fake/engine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright 2016-2024, 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 fake

import (
"context"
"fmt"
"sync"
"testing"

pbempty "github.com/golang/protobuf/ptypes/empty"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/rpcutil"
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

func NewEngineServer(t testing.TB) *EngineServer {
return &EngineServer{t: t}
}

func StartEngineServer(t testing.TB, engine pulumirpc.EngineServer) (addr string) {
cancel := make(chan bool)
t.Cleanup(func() {
close(cancel)
})
handle, err := rpcutil.ServeWithOptions(rpcutil.ServeOptions{
Cancel: cancel,
Init: func(srv *grpc.Server) error {
pulumirpc.RegisterEngineServer(srv, engine)
return nil
},
Options: rpcutil.OpenTracingServerInterceptorOptions(nil),
})
if err != nil {
t.Fatalf("could not start host engine service: %s", err)
}

go func() {
err := <-handle.Done
if err != nil {
t.Errorf("host engine service failed: %s", err)
}
}()

return fmt.Sprintf("127.0.0.1:%v", handle.Port)
}

func ConnectToEngine(t testing.TB, addr string) *grpc.ClientConn {
conn, err := grpc.Dial(
addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithUnaryInterceptor(rpcutil.OpenTracingClientInterceptor()),
grpc.WithStreamInterceptor(rpcutil.OpenTracingStreamClientInterceptor()),
rpcutil.GrpcChannelOptions(),
)
if err != nil {
t.Fatalf("could not connect to host engine service: %s", err)
}
t.Cleanup(func() {
conn.Close()
})

return conn
}

// A fake engine server for test purposes.
type EngineServer struct {
pulumirpc.UnsafeEngineServer
t testing.TB

mu sync.Mutex
rootResource string
logs []*pulumirpc.LogRequest
}

func (m *EngineServer) Logs() []*pulumirpc.LogRequest {
m.mu.Lock()
defer m.mu.Unlock()
var logs []*pulumirpc.LogRequest
logs = append(logs, m.logs...)
return logs
}

var _ pulumirpc.EngineServer = &EngineServer{}

// Log logs a global message in the engine, including errors and warnings.
func (m *EngineServer) Log(ctx context.Context, in *pulumirpc.LogRequest) (*pbempty.Empty, error) {
m.t.Logf("%s: %s", in.GetSeverity(), in.GetMessage())
func() {
m.mu.Lock()
defer m.mu.Unlock()
m.logs = append(m.logs, in)
}()
return &pbempty.Empty{}, nil
}

// GetRootResource gets the URN of the root resource, the resource that should be the root of all
// otherwise-unparented resources.
func (m *EngineServer) GetRootResource(ctx context.Context, in *pulumirpc.GetRootResourceRequest) (*pulumirpc.GetRootResourceResponse, error) {
m.mu.Lock()
defer m.mu.Unlock()
return &pulumirpc.GetRootResourceResponse{
Urn: m.rootResource,
}, nil
}

// SetRootResource sets the URN of the root resource.
func (m *EngineServer) SetRootResource(ctx context.Context, in *pulumirpc.SetRootResourceRequest) (*pulumirpc.SetRootResourceResponse, error) {
m.mu.Lock()
defer m.mu.Unlock()
m.rootResource = in.GetUrn()
return &pulumirpc.SetRootResourceResponse{}, nil
}
186 changes: 186 additions & 0 deletions provider/pkg/host/fake/monitor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Copyright 2016-2024, 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 fake

import (
"context"
"fmt"
"sync"
"testing"

"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"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/rpcutil"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
)

type SimpleMonitor struct {
CallF func(args pulumi.MockCallArgs) (resource.PropertyMap, error)
NewResourceF func(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error)
}

func (m *SimpleMonitor) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
if m.CallF == nil {
return resource.PropertyMap{}, nil
}
return m.CallF(args)
}

func (m *SimpleMonitor) NewResource(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
if m.NewResourceF == nil {
return args.Name, args.Inputs, nil
}
return m.NewResourceF(args)
}

func StartMonitorServer(t testing.TB, monitor pulumirpc.ResourceMonitorServer) (addr string) {
cancel := make(chan bool)
t.Cleanup(func() {
close(cancel)
})
handle, err := rpcutil.ServeWithOptions(rpcutil.ServeOptions{
Cancel: cancel,
Init: func(srv *grpc.Server) error {
pulumirpc.RegisterResourceMonitorServer(srv, monitor)
return nil
},
Options: rpcutil.OpenTracingServerInterceptorOptions(nil),
})
if err != nil {
t.Fatalf("could not start resource monitor service: %s", err)
}

go func() {
err := <-handle.Done
if err != nil {
t.Errorf("resource monitor service failed: %s", err)
}
}()

return fmt.Sprintf("127.0.0.1:%v", handle.Port)
}

func NewResourceMonitorServer(t testing.TB, monitor pulumi.MockResourceMonitor) *ResourceMonitorServer {
return &ResourceMonitorServer{
t: t,
project: "project",
stack: "stack",
mocks: monitor,
resources: map[string]resource.PropertyMap{},
}
}

type ResourceMonitorServer struct {
pulumirpc.UnimplementedResourceMonitorServer
t testing.TB
project string
stack string
mocks pulumi.MockResourceMonitor

mu sync.Mutex
resources map[string]resource.PropertyMap
}

func (m *ResourceMonitorServer) Resources() map[string]resource.PropertyMap {
m.mu.Lock()
defer m.mu.Unlock()
resources := map[string]resource.PropertyMap{}
for k, v := range m.resources {
resources[k] = v
}
return resources
}

var _ pulumirpc.ResourceMonitorServer = &ResourceMonitorServer{}

func (m *ResourceMonitorServer) newURN(parent, typ, name string) string {
parentType := tokens.Type("")
if parentURN := resource.URN(parent); parentURN != "" && parentURN.QualifiedType() != resource.RootStackType {
parentType = parentURN.QualifiedType()
}

return string(resource.NewURN(tokens.QName(m.stack), tokens.PackageName(m.project), parentType, tokens.Type(typ),
name))
}

func (m *ResourceMonitorServer) SupportsFeature(context.Context, *pulumirpc.SupportsFeatureRequest) (*pulumirpc.SupportsFeatureResponse, error) {
return &pulumirpc.SupportsFeatureResponse{
HasSupport: true,
}, nil
}

func (m *ResourceMonitorServer) RegisterResourceOutputs(context.Context, *pulumirpc.RegisterResourceOutputsRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}

func (m *ResourceMonitorServer) RegisterResource(ctx context.Context, in *pulumirpc.RegisterResourceRequest) (*pulumirpc.RegisterResourceResponse, error) {
if in.GetType() == string(resource.RootStackType) && in.GetParent() == "" {
return &pulumirpc.RegisterResourceResponse{
Urn: m.newURN(in.GetParent(), in.GetType(), in.GetName()),
}, nil
}

inputs, err := plugin.UnmarshalProperties(in.GetObject(), plugin.MarshalOptions{
KeepSecrets: true,
KeepResources: true,
})
if err != nil {
return nil, err
}

id, state, err := m.mocks.NewResource(pulumi.MockResourceArgs{
TypeToken: in.GetType(),
Name: in.GetName(),
Inputs: inputs,
Provider: in.GetProvider(),
ID: in.GetImportId(),
Custom: in.GetCustom(),
RegisterRPC: in,
})
if err != nil {
return nil, err
}

urn := m.newURN(in.GetParent(), in.GetType(), in.GetName())

func() {
m.mu.Lock()
defer m.mu.Unlock()
m.resources[urn] = resource.PropertyMap{
resource.PropertyKey("urn"): resource.NewStringProperty(urn),
resource.PropertyKey("id"): resource.NewStringProperty(id),
resource.PropertyKey("state"): resource.NewObjectProperty(state),
resource.PropertyKey("parent"): resource.NewStringProperty(in.GetParent()),
}
}()

stateOut, err := plugin.MarshalProperties(state, plugin.MarshalOptions{
KeepSecrets: true,
KeepResources: true,
})
if err != nil {
return nil, err
}

return &pulumirpc.RegisterResourceResponse{
Urn: urn,
Id: id,
Object: stateOut,
}, nil
}
8 changes: 3 additions & 5 deletions provider/pkg/provider/yaml/v2/configGroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
)

var _ = Describe("Construct", func() {
var tc *resourceProviderTestContext
var tc *componentProviderTestContext
var opts *providerresource.ResourceProviderOptions
var req *pulumirpc.ConstructRequest
var inputs resource.PropertyMap
Expand Down Expand Up @@ -63,16 +63,14 @@ var _ = Describe("Construct", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(resp.Urn).Should(Equal("urn:pulumi:stack::project::kubernetes:yaml/v2:ConfigGroup::test"))

Expect(tc.monitor.resources).To(MatchKeys(IgnoreExtras, Keys{
Expect(tc.monitor.Resources()).To(MatchKeys(IgnoreExtras, Keys{
"urn:pulumi:stack::project::kubernetes:yaml/v2:ConfigGroup::test": MatchProps(IgnoreExtras, Props{
"id": MatchValue("test"),
}),
}))
})

commonAssertions := func() {
PIt("should reflect the input property as an output property")

It("should provide a 'resources' output property", func(ctx context.Context) {
resp, err := pulumiprovider.Construct(ctx, req, tc.EngineConn(), k.Construct)
Expect(err).ShouldNot(HaveOccurred())
Expand Down Expand Up @@ -133,7 +131,7 @@ var _ = Describe("Construct", func() {
It("should emit a warning", func(ctx context.Context) {
_, err := pulumiprovider.Construct(ctx, req, tc.EngineConn(), k.Construct)
Expect(err).ShouldNot(HaveOccurred())
Expect(tc.engine.logs).To(HaveLen(1))
Expect(tc.engine.Logs()).To(HaveLen(1))
})

It("should provide a 'resources' output property", func(ctx context.Context) {
Expand Down
Loading

0 comments on commit a10d723

Please sign in to comment.