github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/controllers/fake/client.go (about)

     1  package fake
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  
     7  	"sigs.k8s.io/controller-runtime/pkg/client"
     8  	ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
     9  
    10  	"github.com/tilt-dev/tilt-apiserver/pkg/server/builder/resource/resourcestrategy"
    11  )
    12  
    13  // Wrap the fake client in other assertions we want to make.
    14  type fakeTiltClient struct {
    15  	ctrlclient.Client
    16  }
    17  
    18  func (f fakeTiltClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
    19  	forCreate := obj.DeepCopyObject().(client.Object)
    20  	if defaulter, ok := forCreate.(resourcestrategy.Defaulter); ok {
    21  		defaulter.Default()
    22  	}
    23  
    24  	if err := f.Client.Create(ctx, forCreate, opts...); err != nil {
    25  		return err
    26  	}
    27  
    28  	return simulateMarshalRoundtrip(forCreate, obj)
    29  }
    30  
    31  func (f fakeTiltClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
    32  	if ctxErr := ctx.Err(); ctxErr != nil {
    33  		// controller-runtime fake ignores context; check it here to allow controllers to test
    34  		// handling of cancellation related errors
    35  		return ctxErr
    36  	}
    37  
    38  	forUpdate := obj.DeepCopyObject().(client.Object)
    39  	if defaulter, ok := forUpdate.(resourcestrategy.Defaulter); ok {
    40  		defaulter.Default()
    41  	}
    42  
    43  	err := f.Client.Update(ctx, forUpdate, opts...)
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	return simulateMarshalRoundtrip(forUpdate, obj)
    49  }
    50  
    51  func (f fakeTiltClient) Status() client.StatusWriter {
    52  	return fakeStatusWriter{f.Client.Status()}
    53  }
    54  
    55  type fakeStatusWriter struct {
    56  	ctrlclient.StatusWriter
    57  }
    58  
    59  func (f fakeStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
    60  	if ctxErr := ctx.Err(); ctxErr != nil {
    61  		// controller-runtime fake ignores context; check it here to allow controllers to test
    62  		// handling of cancellation related errors
    63  		return ctxErr
    64  	}
    65  
    66  	err := f.StatusWriter.Update(ctx, obj, opts...)
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	content, err := json.Marshal(obj)
    72  	if err != nil {
    73  		return err
    74  	}
    75  	return json.Unmarshal(content, obj)
    76  }
    77  
    78  func (f fakeStatusWriter) Patch(ctx context.Context, obj ctrlclient.Object, patch ctrlclient.Patch, opts ...ctrlclient.SubResourcePatchOption) error {
    79  	if ctxErr := ctx.Err(); ctxErr != nil {
    80  		// controller-runtime fake ignores context; check it here to allow controllers to test
    81  		// handling of cancellation related errors
    82  		return ctxErr
    83  	}
    84  
    85  	err := f.StatusWriter.Patch(ctx, obj, patch, opts...)
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	content, err := json.Marshal(obj)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	return json.Unmarshal(content, obj)
    95  }
    96  
    97  // simulateMarshalRoundtrip makes API types behave closer to reality for the
    98  // fake client.
    99  //
   100  // NOTE(nick): We've had a lot of bugs due to the way the apiserver
   101  // modifies and truncates objects on update. We simulate this behavior
   102  // to catch this class of bug.
   103  //
   104  // The `apiResp` argument is marshaled and then unmarshalled into `dest` arg.
   105  // (This allows the fake client to mutate a *copy* of the user-provided obj, and
   106  // only mutate the *original* obj here on success.)
   107  func simulateMarshalRoundtrip(apiResp, dest ctrlclient.Object) error {
   108  	content, err := json.Marshal(apiResp)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	if err := json.Unmarshal(content, dest); err != nil {
   113  		return err
   114  	}
   115  	return nil
   116  }