github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/reconciler/fake.go (about)

     1  package reconciler
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"time"
     7  
     8  	reconcilerApi "github.com/kyma-incubator/reconciler/pkg/keb"
     9  )
    10  
    11  /*
    12  FakeClient is simulating API and db transactions in Reconciler Inventory
    13  
    14    - registeredCluster is representation of 'inventory_clusters' table
    15      each unique clusterVersion should be a separate record
    16    - registeredCluster.clusterConfigs is representation of `inventory_cluster_configs` table
    17      and it is a map[configVersion]Cluster; it stores different clusterConfigs for the same cluster
    18    - registeredCluster.clusterStates is a map[configVersion]State; it simulates returning the status of given cluster in given configVersion
    19    - registeredCluster.statusChanges is representation of 'inventory_cluster_config_statuses' table
    20      and it is a slice of *StatusChange; it contains all status changes for the cluster
    21  
    22  calling ApplyClusterConfig method on already existing cluster results in adding a new ClusterConfig
    23  */
    24  type FakeClient struct {
    25  	mu                sync.Mutex
    26  	inventoryClusters map[string]*registeredCluster
    27  	deleted           map[string]struct{}
    28  }
    29  
    30  type registeredCluster struct {
    31  	clusterConfigs map[int64]reconcilerApi.Cluster
    32  	clusterStates  map[int64]*reconcilerApi.HTTPClusterResponse
    33  	statusChanges  []*reconcilerApi.StatusChange
    34  }
    35  
    36  func NewFakeClient() *FakeClient {
    37  	return &FakeClient{inventoryClusters: map[string]*registeredCluster{}, deleted: map[string]struct{}{}}
    38  }
    39  
    40  // POST /v1/clusters
    41  func (c *FakeClient) ApplyClusterConfig(cluster reconcilerApi.Cluster) (*reconcilerApi.HTTPClusterResponse, error) {
    42  	return c.addToInventory(cluster)
    43  }
    44  
    45  // DELETE /v1/clusters/{clusterName}
    46  func (c *FakeClient) DeleteCluster(clusterName string) error {
    47  	c.mu.Lock()
    48  	defer c.mu.Unlock()
    49  	_, exists := c.inventoryClusters[clusterName]
    50  	if !exists {
    51  		return nil
    52  	}
    53  	c.deleted[clusterName] = struct{}{}
    54  	return nil
    55  }
    56  
    57  // GET /v1/clusters/{clusterName}/configs/{configVersion}/status
    58  func (c *FakeClient) GetCluster(clusterName string, configVersion int64) (*reconcilerApi.HTTPClusterResponse, error) {
    59  	c.mu.Lock()
    60  	defer c.mu.Unlock()
    61  
    62  	existingCluster, exists := c.inventoryClusters[clusterName]
    63  	if !exists {
    64  		return &reconcilerApi.HTTPClusterResponse{}, fmt.Errorf("not found")
    65  	}
    66  	state, exists := existingCluster.clusterStates[configVersion]
    67  	if !exists {
    68  		return &reconcilerApi.HTTPClusterResponse{}, fmt.Errorf("not found")
    69  	}
    70  	return state, nil
    71  }
    72  
    73  // GET v1/clusters/{clusterName}/status
    74  func (c *FakeClient) GetLatestCluster(clusterName string) (*reconcilerApi.HTTPClusterResponse, error) {
    75  	c.mu.Lock()
    76  	defer c.mu.Unlock()
    77  
    78  	existingCluster, exists := c.inventoryClusters[clusterName]
    79  	if !exists {
    80  		return &reconcilerApi.HTTPClusterResponse{}, nil
    81  	}
    82  	latestConfigVersion := int64(len(existingCluster.clusterStates))
    83  
    84  	return existingCluster.clusterStates[latestConfigVersion], nil
    85  }
    86  
    87  // GET v1/clusters/{clusterName}/statusChanges/{offset}
    88  // offset is parsed to time.Duration
    89  func (c *FakeClient) GetStatusChange(clusterName, offset string) ([]*reconcilerApi.StatusChange, error) {
    90  	c.mu.Lock()
    91  	defer c.mu.Unlock()
    92  
    93  	existingCluster, exists := c.inventoryClusters[clusterName]
    94  	if !exists {
    95  		return []*reconcilerApi.StatusChange{}, nil
    96  	}
    97  	return existingCluster.statusChanges, nil
    98  }
    99  
   100  func (c *FakeClient) addToInventory(cluster reconcilerApi.Cluster) (*reconcilerApi.HTTPClusterResponse, error) {
   101  	c.mu.Lock()
   102  	defer c.mu.Unlock()
   103  
   104  	_, exists := c.inventoryClusters[cluster.RuntimeID]
   105  
   106  	// initial creation call - cluster does not exist in db
   107  	if !exists {
   108  		c.inventoryClusters[cluster.RuntimeID] = &registeredCluster{
   109  			clusterConfigs: map[int64]reconcilerApi.Cluster{
   110  				1: cluster,
   111  			},
   112  			clusterStates: map[int64]*reconcilerApi.HTTPClusterResponse{
   113  				1: {
   114  					Cluster:              cluster.RuntimeID,
   115  					ClusterVersion:       1,
   116  					ConfigurationVersion: 1,
   117  					Status:               "reconcile_pending",
   118  				},
   119  			},
   120  			statusChanges: []*reconcilerApi.StatusChange{{
   121  				Status:   reconcilerApi.StatusReconcilePending,
   122  				Duration: int64(10 * time.Second),
   123  			}},
   124  		}
   125  
   126  		return c.inventoryClusters[cluster.RuntimeID].clusterStates[1], nil
   127  	}
   128  	// cluster exists in db - add new configuration version
   129  	latestConfigVersion := int64(len(c.inventoryClusters[cluster.RuntimeID].clusterStates)) + 1
   130  	c.inventoryClusters[cluster.RuntimeID].clusterStates[latestConfigVersion] = &reconcilerApi.HTTPClusterResponse{
   131  		Cluster:              cluster.RuntimeID,
   132  		ClusterVersion:       1,
   133  		ConfigurationVersion: latestConfigVersion,
   134  		Status:               "reconcile_pending",
   135  	}
   136  	c.inventoryClusters[cluster.RuntimeID].statusChanges = append(c.inventoryClusters[cluster.RuntimeID].statusChanges, &reconcilerApi.StatusChange{
   137  		Status:   reconcilerApi.StatusReconcilePending,
   138  		Duration: int64(10 * time.Second),
   139  	})
   140  	c.inventoryClusters[cluster.RuntimeID].clusterConfigs[latestConfigVersion] = cluster
   141  
   142  	return c.inventoryClusters[cluster.RuntimeID].clusterStates[latestConfigVersion], nil
   143  }
   144  
   145  func (c *FakeClient) ChangeClusterState(clusterName string, clusterVersion int64, desiredState reconcilerApi.Status) {
   146  	c.mu.Lock()
   147  	defer c.mu.Unlock()
   148  
   149  	c.inventoryClusters[clusterName].clusterStates[clusterVersion].Status = desiredState
   150  	c.inventoryClusters[clusterName].statusChanges = append(c.inventoryClusters[clusterName].statusChanges, &reconcilerApi.StatusChange{
   151  		Status:   desiredState,
   152  		Duration: int64(10 * time.Second),
   153  	})
   154  }
   155  
   156  func (c *FakeClient) LastClusterConfig(runtimeID string) (*reconcilerApi.Cluster, error) {
   157  	cluster, found := c.inventoryClusters[runtimeID]
   158  	if !found {
   159  		return nil, fmt.Errorf("cluster not found in clusters inventory")
   160  	}
   161  	return getLastClusterConfig(cluster)
   162  }
   163  
   164  func (c *FakeClient) IsBeingDeleted(id string) bool {
   165  	c.mu.Lock()
   166  	defer c.mu.Unlock()
   167  	_, exists := c.deleted[id]
   168  	if exists {
   169  		return true
   170  	}
   171  
   172  	return false
   173  }
   174  
   175  func (c *FakeClient) ClusterExists(id string) bool {
   176  	_, found := c.inventoryClusters[id]
   177  	return found
   178  }
   179  
   180  func getLastClusterConfig(cluster *registeredCluster) (*reconcilerApi.Cluster, error) {
   181  	clusterConfig, found := cluster.clusterConfigs[int64(len(cluster.clusterConfigs))]
   182  	if !found {
   183  		return nil, fmt.Errorf("cluster config not found in cluster configs inventory")
   184  	}
   185  	return &clusterConfig, nil
   186  }