github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/system/bus/topic_test.go (about)

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 2023, Filippov Alex
     4  //
     5  // This library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU Lesser General Public
     7  // License as published by the Free Software Foundation; either
     8  // version 3 of the License, or (at your option) any later version.
     9  //
    10  // This library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  // Library General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public
    16  // License along with this library.  If not, see
    17  // <https://www.gnu.org/licenses/>.
    18  
    19  package bus
    20  
    21  import (
    22  	"fmt"
    23  	"go.uber.org/atomic"
    24  	"reflect"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  func TestTopic(t *testing.T) {
    33  
    34  	const topic = "test/topic"
    35  
    36  	b := NewTopic(topic)
    37  
    38  	var counter = 0
    39  	var wg = sync.WaitGroup{}
    40  
    41  	// Test Subscribe
    42  	fn := func(topic string, arg1 string, arg2 string) {
    43  		counter++
    44  		wg.Done()
    45  	}
    46  	wg.Add(1)
    47  	err := b.Subscribe(fn)
    48  	if err != nil {
    49  		t.Errorf("Subscribe returned an error: %v", err)
    50  	}
    51  
    52  	// Test Publish
    53  	b.Publish("hello", "world")
    54  
    55  	wg.Wait()
    56  
    57  	require.Equal(t, counter, 1)
    58  
    59  	// ------------------------------------------------------------
    60  	// Test Stat
    61  	stat := b.Stat()
    62  	require.Equal(t, stat.Topic, topic)
    63  	require.Equal(t, stat.Subscribers, 1)
    64  
    65  	// ------------------------------------------------------------
    66  
    67  	// Test Unsubscribe
    68  	empty, err := b.Unsubscribe(fn)
    69  	if err != nil {
    70  		t.Errorf("Unsubscribe returned an error: %v", err)
    71  	}
    72  	require.Equal(t, true, empty)
    73  
    74  	// Test Publish
    75  	b.Publish("hello", "world")
    76  
    77  	time.Sleep(time.Second)
    78  
    79  	require.Equal(t, 1, counter)
    80  
    81  	// ------------------------------------------------------------
    82  
    83  	stat = b.Stat()
    84  	require.Equal(t, stat.Topic, topic)
    85  	require.Equal(t, stat.Subscribers, 0)
    86  	// ------------------------------------------------------------
    87  
    88  	// Test Subscribe
    89  	fn = func(topic string, arg1 string, arg2 string) {
    90  		counter++
    91  	}
    92  	err = b.Subscribe(fn, false)
    93  	if err != nil {
    94  		t.Errorf("Subscribe returned an error: %v", err)
    95  	}
    96  
    97  	stat = b.Stat()
    98  	require.Equal(t, stat.Subscribers, 1)
    99  
   100  	// Test Close
   101  	b.Close()
   102  
   103  	stat = b.Stat()
   104  	require.Equal(t, stat.Subscribers, 0)
   105  
   106  	// Test Publish
   107  	b.Publish("foo", "bar")
   108  
   109  	time.Sleep(time.Second)
   110  
   111  	require.Equal(t, 1, counter)
   112  
   113  	// ------------------------------------------------------------
   114  	// Test Stat
   115  	stat = b.Stat()
   116  	require.Equal(t, stat.Subscribers, 0)
   117  	// ------------------------------------------------------------
   118  
   119  	fn = func(topic string, arg1 string, arg2 string) {
   120  		counter++
   121  	}
   122  	err = b.Subscribe(fn, false)
   123  	if err != nil {
   124  		t.Errorf("Subscribe returned an error: %v", err)
   125  	}
   126  
   127  	// Test Close
   128  	b.Close()
   129  
   130  	// Test Publish
   131  	b.Publish("hello", "world")
   132  
   133  	time.Sleep(time.Second)
   134  
   135  	require.Equal(t, 1, counter)
   136  
   137  	/// Test Stat
   138  	stat = b.Stat()
   139  	require.Equal(t, stat.Subscribers, 0)
   140  
   141  	// ------------------------------------------------------------
   142  
   143  	// Test buildHandlerArgs
   144  	args := buildHandlerArgs([]interface{}{topic, "hello", "world"})
   145  	if len(args) != 3 {
   146  		t.Errorf("buildHandlerArgs returned the wrong number of arguments: %v", args)
   147  	}
   148  	if args[0].String() != topic {
   149  		t.Errorf("buildHandlerArgs returned the wrong topic: %v", args[0])
   150  	}
   151  	if args[1].String() != "hello" {
   152  		t.Errorf("buildHandlerArgs returned the wrong arg1: %v", args[1])
   153  	}
   154  	if args[2].String() != "world" {
   155  		t.Errorf("buildHandlerArgs returned the wrong arg2: %v", args[2])
   156  	}
   157  
   158  	// Test reflection of buildHandlerArgs
   159  	if reflect.TypeOf(buildHandlerArgs).Kind() != reflect.Func {
   160  		t.Errorf("buildHandlerArgs is not a function")
   161  	}
   162  }
   163  
   164  func TestTopic2(t *testing.T) {
   165  
   166  	const topic = "test/topic"
   167  
   168  	b := NewTopic(topic)
   169  
   170  	var counter atomic.Int32
   171  	var wg = sync.WaitGroup{}
   172  
   173  	// Test Subscribe
   174  	fn := func(topic string, arg1 string, arg2 string) {
   175  		fmt.Println("fn1")
   176  		counter.Inc()
   177  		wg.Done()
   178  	}
   179  
   180  	fn2 := func(topic string, arg1 string, arg2 string) {
   181  		fmt.Println("fn2")
   182  		counter.Inc()
   183  		wg.Done()
   184  	}
   185  
   186  	fn3 := func(topic string, arg1 string, arg2 string) {
   187  		fmt.Println("fn3")
   188  		counter.Inc()
   189  		wg.Done()
   190  	}
   191  
   192  	wg.Add(3)
   193  
   194  	err := b.Subscribe(fn)
   195  	if err != nil {
   196  		t.Errorf("Subscribe returned an error: %v", err)
   197  	}
   198  	err = b.Subscribe(fn2)
   199  	if err != nil {
   200  		t.Errorf("Subscribe returned an error: %v", err)
   201  	}
   202  	err = b.Subscribe(fn3)
   203  	if err != nil {
   204  		t.Errorf("Subscribe returned an error: %v", err)
   205  	}
   206  
   207  	// Test Stat
   208  	stat := b.Stat()
   209  	require.Equal(t, 3, stat.Subscribers)
   210  
   211  	// Test Publish
   212  	b.Publish("hello", "world")
   213  
   214  	wg.Wait()
   215  
   216  	require.Equal(t, int32(3), counter.Load())
   217  }
   218  
   219  func TestTopic3(t *testing.T) {
   220  
   221  	const topic = "test/topic"
   222  
   223  	b := NewTopic(topic)
   224  
   225  	// Test Subscribe
   226  	fn := func(topic string, arg1 string, arg2 string) {}
   227  
   228  	empty, err := b.Unsubscribe(fn)
   229  	require.Equal(t, nil, err)
   230  	require.Equal(t, true, empty)
   231  
   232  	err = b.Subscribe(fn)
   233  	require.Equal(t, nil, err)
   234  
   235  	// Test Stat
   236  	stat := b.Stat()
   237  	require.Equal(t, 1, stat.Subscribers)
   238  
   239  	empty, err = b.Unsubscribe(fn)
   240  	require.Equal(t, nil, err)
   241  	require.Equal(t, true, empty)
   242  
   243  	empty, err = b.Unsubscribe(fn)
   244  	require.Equal(t, nil, err)
   245  	require.Equal(t, true, empty)
   246  }
   247  
   248  func BenchmarkTopic(b *testing.B) {
   249  
   250  	const topic = "test/topic"
   251  
   252  	bus := NewTopic(topic)
   253  
   254  	var counter atomic.Int32
   255  
   256  	// Test Subscribe
   257  	fn := func(topic string, arg1 string, arg2 string) {
   258  		counter.Inc()
   259  	}
   260  	err := bus.Subscribe(fn)
   261  	require.NoError(b, err)
   262  
   263  	b.ResetTimer()
   264  	for i := 0; i < b.N; i++ {
   265  		bus.Publish("hello", "world")
   266  	}
   267  
   268  	time.Sleep(time.Second)
   269  
   270  	require.Equal(b, int32(b.N), counter.Load())
   271  }