github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/in10nmem/v1/impl_test.go (about)

     1  /*
     2   * Copyright (c) 2021-present Sigma-Soft, Ltd.
     3   * Aleksei Ponomarev
     4   */
     5  
     6  package in10nmemv1
     7  
     8  import (
     9  	"context"
    10  	"strconv"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/stretchr/testify/require"
    16  	"github.com/voedger/voedger/pkg/appdef"
    17  	"github.com/voedger/voedger/pkg/in10n"
    18  	istructs "github.com/voedger/voedger/pkg/istructs"
    19  )
    20  
    21  type callbackMock struct {
    22  	wait chan UpdateUnit
    23  }
    24  
    25  func TestBasicUsage(t *testing.T) {
    26  	var wg sync.WaitGroup
    27  	c := new(callbackMock)
    28  	c.wait = make(chan UpdateUnit)
    29  
    30  	projectionKeyExample := in10n.ProjectionKey{
    31  		App:        istructs.AppQName_test1_app1,
    32  		Projection: appdef.NewQName("test", "restaurant"),
    33  		WS:         istructs.WSID(0),
    34  	}
    35  
    36  	quotasExample := in10n.Quotas{
    37  		Channels:                1,
    38  		ChannelsPerSubject:      1,
    39  		Subscriptions:           1,
    40  		SubscriptionsPerSubject: 1,
    41  	}
    42  	req := require.New(t)
    43  	ctx, cancel := context.WithCancel(context.Background())
    44  
    45  	broker := Provide(quotasExample)
    46  
    47  	var channel in10n.ChannelID
    48  	t.Run("Create channel.", func(t *testing.T) {
    49  		var subject istructs.SubjectLogin = "paa"
    50  		var err error
    51  		channel, err = broker.NewChannel(subject, 24*time.Hour)
    52  		req.NoError(err)
    53  		req.NotNil(channel)
    54  	})
    55  
    56  	t.Run("Check channel count. count must be 1.", func(t *testing.T) {
    57  		numChannels := broker.MetricNumChannels()
    58  		req.Equal(1, numChannels)
    59  	})
    60  
    61  	wg.Add(1)
    62  	go func() {
    63  		defer wg.Done()
    64  		broker.WatchChannel(ctx, channel, c.updatesMock)
    65  	}()
    66  
    67  	t.Run("Subscribe on projection.", func(t *testing.T) {
    68  		var notExistsChannel = "NotExistChannel"
    69  		// Try to subscribe on projection in not exist channel
    70  		// must receive error ErrChannelNotExists
    71  		err := broker.Subscribe(in10n.ChannelID(notExistsChannel), projectionKeyExample)
    72  		req.ErrorIs(err, in10n.ErrChannelDoesNotExist)
    73  
    74  		// check subscriptions, numSubscriptions must be equal 0
    75  		numSubscriptions := broker.MetricNumSubcriptions()
    76  		req.Equal(0, numSubscriptions)
    77  
    78  		// Subscribe on exist channel numSubscriptions must be equal 1
    79  		require.NoError(t, broker.Subscribe(channel, projectionKeyExample))
    80  		numSubscriptions = broker.MetricNumSubcriptions()
    81  		req.Equal(1, numSubscriptions)
    82  
    83  		// Unsubscribe from not exist channel, raise error in10n.ErrChannelDoesNotExist
    84  		err = broker.Unsubscribe("Not exists channel", projectionKeyExample)
    85  		req.ErrorIs(err, in10n.ErrChannelDoesNotExist)
    86  
    87  		// Unsubscribe from exist channel
    88  		err = broker.Unsubscribe(channel, projectionKeyExample)
    89  		req.NoError(err)
    90  		// After unsubscribe numSubscriptions must be equal 0
    91  		numSubscriptions = broker.MetricNumSubcriptions()
    92  		req.Equal(0, numSubscriptions)
    93  
    94  		// Subscribe on exist channel numSubscriptions must be equal 1
    95  		require.NoError(t, broker.Subscribe(channel, projectionKeyExample))
    96  		numSubscriptions = broker.MetricNumSubcriptions()
    97  		req.Equal(1, numSubscriptions)
    98  
    99  	})
   100  
   101  	broker.Update(projectionKeyExample, istructs.Offset(122))
   102  	broker.Update(projectionKeyExample, istructs.Offset(123))
   103  	broker.Update(projectionKeyExample, istructs.Offset(124))
   104  	broker.Update(projectionKeyExample, istructs.Offset(125))
   105  	broker.Update(projectionKeyExample, istructs.Offset(126))
   106  
   107  	for update := range c.wait {
   108  		if update.Offset == istructs.Offset(126) {
   109  			break
   110  		}
   111  	}
   112  	cancel()
   113  	wg.Wait()
   114  }
   115  
   116  func (c *callbackMock) updatesMock(projection in10n.ProjectionKey, offset istructs.Offset) {
   117  	var unit = UpdateUnit{
   118  		Projection: projection,
   119  		Offset:     offset,
   120  	}
   121  	c.wait <- unit
   122  }
   123  
   124  // Try watch on not exists channel. WatchChannel must exit.
   125  func TestWatchNotExistsChannel(t *testing.T) {
   126  	req := require.New(t)
   127  
   128  	quotasExample := in10n.Quotas{
   129  		Channels:                1,
   130  		ChannelsPerSubject:      1,
   131  		Subscriptions:           1,
   132  		SubscriptionsPerSubject: 1,
   133  	}
   134  
   135  	broker := Provide(quotasExample)
   136  	ctx := context.TODO()
   137  
   138  	t.Run("Create channel.", func(t *testing.T) {
   139  		var subject istructs.SubjectLogin = "paa"
   140  		channel, err := broker.NewChannel(subject, 24*time.Hour)
   141  		req.NoError(err)
   142  		req.NotNil(channel)
   143  	})
   144  
   145  	t.Run("Try watch not exist channel", func(t *testing.T) {
   146  		req.Panics(func() {
   147  			broker.WatchChannel(ctx, "not exist channel id", nil)
   148  		}, "When try watch not exists channel - must panics")
   149  
   150  	})
   151  }
   152  
   153  func TestQuotas(t *testing.T) {
   154  	req := require.New(t)
   155  	quotasExample := in10n.Quotas{
   156  		Channels:                100,
   157  		ChannelsPerSubject:      10,
   158  		Subscriptions:           1000,
   159  		SubscriptionsPerSubject: 100,
   160  	}
   161  
   162  	t.Run("Test channel quotas per subject. We create more channels than allowed for subject.", func(t *testing.T) {
   163  		broker := Provide(quotasExample)
   164  		for i := 0; i <= 10; i++ {
   165  			_, err := broker.NewChannel("paa", 24*time.Hour)
   166  			if i == 10 {
   167  				req.ErrorIs(err, in10n.ErrQuotaExceeded_ChannelsPerSubject)
   168  			}
   169  		}
   170  	})
   171  
   172  	t.Run("Test channel quotas for the whole service. We create more channels than allowed for service.", func(t *testing.T) {
   173  		broker := Provide(quotasExample)
   174  		var subject istructs.SubjectLogin
   175  		for i := 0; i < 10; i++ {
   176  			subject = istructs.SubjectLogin("paa" + strconv.Itoa(i))
   177  			for c := 0; c <= 10; c++ {
   178  				_, err := broker.NewChannel(subject, 24*time.Hour)
   179  				if i == 9 && c == 10 {
   180  					req.ErrorIs(err, in10n.ErrQuotaExceeded_Channels)
   181  				}
   182  			}
   183  		}
   184  	})
   185  
   186  	t.Run("Test subscription quotas for the whole service. We create more subscription than allowed for service.", func(t *testing.T) {
   187  		projectionKeyExample := in10n.ProjectionKey{
   188  			App:        istructs.AppQName_test1_app1,
   189  			Projection: appdef.NewQName("test", "restaurant"),
   190  			WS:         istructs.WSID(1),
   191  		}
   192  		broker := Provide(quotasExample)
   193  		var subject istructs.SubjectLogin
   194  		for i := 0; i < 100; i++ {
   195  			subject = istructs.SubjectLogin("paa" + strconv.Itoa(i))
   196  			channel, err := broker.NewChannel(subject, 24*time.Hour)
   197  			req.NoError(err)
   198  			for g := 0; g < 10; g++ {
   199  				projectionKeyExample.WS = istructs.WSID(i + g)
   200  				err = broker.Subscribe(channel, projectionKeyExample)
   201  				req.NoError(err)
   202  				if i == 99 && g == 9 {
   203  					numSubscriptions := broker.MetricNumSubcriptions()
   204  					req.Equal(1000, numSubscriptions)
   205  					projectionKeyExample.WS = istructs.WSID(i + 100000)
   206  					err = broker.Subscribe(channel, projectionKeyExample)
   207  					req.ErrorIs(err, in10n.ErrQuotaExceeded_Subsciptions)
   208  				}
   209  			}
   210  		}
   211  
   212  	})
   213  
   214  }