github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/service/session_pool_test.go (about)

     1  /*
     2   * Copyright (C) 2018 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package service
    19  
    20  import (
    21  	"fmt"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/mysteriumnetwork/node/mocks"
    26  	"github.com/mysteriumnetwork/node/pb"
    27  	"github.com/mysteriumnetwork/node/session"
    28  	sessionEvent "github.com/mysteriumnetwork/node/session/event"
    29  	"github.com/mysteriumnetwork/node/trace"
    30  	"github.com/stretchr/testify/assert"
    31  )
    32  
    33  var (
    34  	sessionExisting, _ = NewSession(
    35  		&Instance{ID: "1"},
    36  		&pb.SessionRequest{Consumer: &pb.ConsumerInfo{Id: "deadbeef"}},
    37  		trace.NewTracer(""),
    38  	)
    39  )
    40  
    41  func TestSessionPool_FindSession_Existing(t *testing.T) {
    42  	pool := mockPool(mocks.NewEventBus(), sessionExisting)
    43  
    44  	sessionInstance, found := pool.Find(sessionExisting.ID)
    45  
    46  	assert.True(t, found)
    47  	assert.Exactly(t, sessionExisting, sessionInstance)
    48  }
    49  
    50  func TestSessionPool_FindSession_Unknown(t *testing.T) {
    51  	storage := mockPool(mocks.NewEventBus(), sessionExisting)
    52  
    53  	sessionInstance, found := storage.Find(session.ID("unknown-id"))
    54  	assert.False(t, found)
    55  	assert.Nil(t, sessionInstance)
    56  }
    57  
    58  func TestSessionPool_Add(t *testing.T) {
    59  	pool := mockPool(mocks.NewEventBus(), sessionExisting)
    60  	sessionNew, _ := NewSession(&Instance{}, &pb.SessionRequest{}, trace.NewTracer(""))
    61  
    62  	pool.Add(sessionNew)
    63  	assert.Exactly(
    64  		t,
    65  		map[session.ID]*Session{sessionExisting.ID: sessionExisting, sessionNew.ID: sessionNew},
    66  		pool.sessions,
    67  	)
    68  }
    69  
    70  func TestSessionPool_Add_PublishesEvents(t *testing.T) {
    71  	// given
    72  	session, _ := NewSession(&Instance{}, &pb.SessionRequest{}, trace.NewTracer(""))
    73  	mp := mocks.NewEventBus()
    74  	pool := NewSessionPool(mp)
    75  
    76  	// when
    77  	pool.Add(session)
    78  
    79  	// then
    80  	assert.Eventually(t, lastEventMatches(mp, session.ID, sessionEvent.CreatedStatus), 2*time.Second, 10*time.Millisecond)
    81  }
    82  
    83  func TestSessionPool_FindByPeer(t *testing.T) {
    84  	pool := mockPool(mocks.NewEventBus(), sessionExisting)
    85  	session, ok := pool.FindBy(FindOpts{&sessionExisting.ConsumerID, ""})
    86  	assert.True(t, ok)
    87  	assert.Equal(t, sessionExisting.ID, session.ID)
    88  }
    89  
    90  func TestSessionPool_GetAll(t *testing.T) {
    91  	sessionFirst, _ := NewSession(&Instance{}, &pb.SessionRequest{}, trace.NewTracer(""))
    92  	sessionSecond, _ := NewSession(&Instance{}, &pb.SessionRequest{}, trace.NewTracer(""))
    93  
    94  	pool := &SessionPool{
    95  		sessions: map[session.ID]*Session{
    96  			sessionFirst.ID:  sessionFirst,
    97  			sessionSecond.ID: sessionSecond,
    98  		},
    99  	}
   100  
   101  	sessions := pool.GetAll()
   102  	assert.Contains(t, sessions, sessionFirst)
   103  	assert.Contains(t, sessions, sessionSecond)
   104  }
   105  
   106  func TestSessionPool_Remove(t *testing.T) {
   107  	pool := mockPool(mocks.NewEventBus(), sessionExisting)
   108  
   109  	pool.Remove(sessionExisting.ID)
   110  	assert.Len(t, pool.sessions, 0)
   111  }
   112  
   113  func TestSessionPool_RemoveNonExisting(t *testing.T) {
   114  	pool := &SessionPool{
   115  		sessions:  map[session.ID]*Session{},
   116  		publisher: mocks.NewEventBus(),
   117  	}
   118  	pool.Remove(sessionExisting.ID)
   119  	assert.Len(t, pool.sessions, 0)
   120  }
   121  
   122  func TestSessionPool_Remove_Does_Not_Panic(t *testing.T) {
   123  	pool := mockPool(mocks.NewEventBus(), sessionExisting)
   124  
   125  	sessionFirst, _ := NewSession(&Instance{}, &pb.SessionRequest{}, trace.NewTracer(""))
   126  	pool.Add(sessionFirst)
   127  
   128  	sessionSecond, _ := NewSession(&Instance{}, &pb.SessionRequest{}, trace.NewTracer(""))
   129  	pool.Add(sessionSecond)
   130  
   131  	pool.Remove(sessionFirst.ID)
   132  	pool.Remove(sessionSecond.ID)
   133  	assert.Len(t, pool.sessions, 1)
   134  }
   135  
   136  func TestSessionPool_Remove_PublishesEvents(t *testing.T) {
   137  	// given
   138  	mp := mocks.NewEventBus()
   139  	pool := mockPool(mp, sessionExisting)
   140  
   141  	// when
   142  	pool.Remove(sessionExisting.ID)
   143  
   144  	// then
   145  	assert.Eventually(t, lastEventMatches(mp, sessionExisting.ID, sessionEvent.RemovedStatus), 2*time.Second, 10*time.Millisecond)
   146  }
   147  
   148  func TestSessionPool_RemoveForService_PublishesEvents(t *testing.T) {
   149  	// given
   150  	mp := mocks.NewEventBus()
   151  	pool := mockPool(mp, sessionExisting)
   152  
   153  	// when
   154  	pool.RemoveForService(sessionExisting.ServiceID)
   155  
   156  	// then
   157  	assert.Eventually(t, lastEventMatches(mp, sessionExisting.ID, sessionEvent.RemovedStatus), 2*time.Second, 10*time.Millisecond)
   158  }
   159  
   160  func mockPool(publisher publisher, sessionInstance *Session) *SessionPool {
   161  	return &SessionPool{
   162  		sessions:  map[session.ID]*Session{sessionInstance.ID: sessionInstance},
   163  		publisher: publisher,
   164  	}
   165  }
   166  
   167  func lastEventMatches(mp *mocks.EventBus, id session.ID, action sessionEvent.Status) func() bool {
   168  	return func() bool {
   169  		last := mp.Pop()
   170  		evt, ok := last.(sessionEvent.AppEventSession)
   171  		if !ok {
   172  			return false
   173  		}
   174  		return evt.Session.ID == string(id) && evt.Status == action
   175  	}
   176  }
   177  
   178  // to avoid compiler optimizing away our bench
   179  var benchmarkSessionPoolGetAllResult int
   180  
   181  func Benchmark_SessionPool_GetAll(b *testing.B) {
   182  	// Findings are as follows - with 100k sessions, we should be fine with a performance of 0.04s on my mac
   183  	pool := NewSessionPool(mocks.NewEventBus())
   184  	sessionsToStore := 100000
   185  	for i := 0; i < sessionsToStore; i++ {
   186  		pool.Add(&Session{ID: session.ID(fmt.Sprintf("ID%v", i)), CreatedAt: time.Now()})
   187  	}
   188  
   189  	var r int
   190  	for n := 0; n < b.N; n++ {
   191  		storedValues := pool.GetAll()
   192  		r += len(storedValues)
   193  	}
   194  	benchmarkSessionPoolGetAllResult = r
   195  }