github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/integration/suites/rpcutil/rpcutil_test.go (about)

     1  // Copyright (c) 2022, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package rpcutil
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"path/filepath"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/choria-io/go-choria/build"
    16  	"github.com/choria-io/go-choria/choria"
    17  	"github.com/choria-io/go-choria/client/rpcutilclient"
    18  	"github.com/choria-io/go-choria/config"
    19  	"github.com/choria-io/go-choria/integration/testbroker"
    20  	"github.com/choria-io/go-choria/integration/testutil"
    21  	"github.com/choria-io/go-choria/providers/agent/mcorpc"
    22  	"github.com/choria-io/go-choria/providers/agent/mcorpc/golang/rpcutil"
    23  	"github.com/choria-io/go-choria/server"
    24  	. "github.com/onsi/ginkgo/v2"
    25  	. "github.com/onsi/gomega"
    26  	"github.com/onsi/gomega/gbytes"
    27  	"github.com/sirupsen/logrus"
    28  )
    29  
    30  func TestRPCUtilAgent(t *testing.T) {
    31  	RegisterFailHandler(Fail)
    32  	RunSpecs(t, "Integration/rpcutil Agent")
    33  }
    34  
    35  var _ = Describe("rpcutil agent", func() {
    36  	var (
    37  		ctx           context.Context
    38  		cancel        context.CancelFunc
    39  		wg            sync.WaitGroup
    40  		srv           *server.Instance
    41  		err           error
    42  		rpcutilAgent  *mcorpc.Agent
    43  		rpcutilClient *rpcutilclient.RpcutilClient
    44  		brokerLogger  *logrus.Logger
    45  		brokerLogbuff *gbytes.Buffer
    46  		serverLogbuff *gbytes.Buffer
    47  	)
    48  
    49  	startServerInstance := func(cfgFile string, logbuff *gbytes.Buffer) (*server.Instance, error) {
    50  		logger := logrus.New()
    51  		logger.SetOutput(logbuff)
    52  
    53  		srv, err = testutil.StartServerInstance(ctx, &wg, cfgFile, logger, testutil.ServerWithRPCUtilAgent())
    54  		Expect(err).ToNot(HaveOccurred())
    55  
    56  		Eventually(logbuff).Should(gbytes.Say("Connected to nats://localhost:4222"))
    57  
    58  		rpcutilAgent, err = rpcutil.New(srv.AgentManager())
    59  		Expect(err).ToNot(HaveOccurred())
    60  
    61  		return srv, nil
    62  	}
    63  
    64  	createRpcUtilClient := func() (*gbytes.Buffer, *rpcutilclient.RpcutilClient, error) {
    65  		logBuff, logger := testutil.GbytesLogger(logrus.DebugLevel)
    66  
    67  		cfg, err := config.NewConfig("testdata/client.conf")
    68  		if err != nil {
    69  			return nil, nil, err
    70  		}
    71  
    72  		cfg.CustomLogger = logger
    73  		cfg.OverrideCertname = "rip.mcollective"
    74  
    75  		fw, err := choria.NewWithConfig(cfg)
    76  		if err != nil {
    77  			return nil, nil, err
    78  		}
    79  
    80  		client, err := rpcutilclient.New(fw)
    81  		if err != nil {
    82  			return nil, nil, err
    83  		}
    84  
    85  		return logBuff, client, nil
    86  	}
    87  
    88  	BeforeEach(func() {
    89  		ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
    90  		DeferCleanup(func() {
    91  			cancel()
    92  			Eventually(brokerLogbuff, 5).Should(gbytes.Say("Choria Network Broker shut down"))
    93  		})
    94  
    95  		brokerLogbuff, brokerLogger = testutil.GbytesLogger(logrus.DebugLevel)
    96  		serverLogbuff = gbytes.NewBuffer()
    97  
    98  		_, err := testbroker.StartNetworkBrokerWithConfigFile(ctx, &wg, "testdata/broker.conf", brokerLogger)
    99  		Expect(err).ToNot(HaveOccurred())
   100  		Eventually(brokerLogbuff, 1).Should(gbytes.Say("Server is ready"))
   101  
   102  		srv, err = startServerInstance("testdata/server.conf", serverLogbuff)
   103  		Expect(err).ToNot(HaveOccurred())
   104  		Eventually(serverLogbuff).Should(gbytes.Say("Registering new agent rpcutil of type rpcutil"))
   105  
   106  		_, rpcutilClient, err = createRpcUtilClient()
   107  		Expect(err).ToNot(HaveOccurred())
   108  	})
   109  
   110  	Describe("Agent", func() {
   111  		It("Should create all actions we support", func() {
   112  			Expect(rpcutilAgent.ActionNames()).To(Equal([]string{"agent_inventory", "collective_info", "daemon_stats", "get_config_item", "get_data", "get_fact", "get_facts", "inventory", "ping"}))
   113  		})
   114  	})
   115  
   116  	Describe("agent_inventory action", func() {
   117  		It("Should get the right inventory", func() {
   118  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).AgentInventory().Do(ctx)
   119  			Expect(err).ToNot(HaveOccurred())
   120  			Expect(res.Stats().OKCount()).To(Equal(1))
   121  
   122  			r := rpcutil.AgentInventoryReply{}
   123  			Expect(res.AllOutputs()[0].ParseAgentInventoryOutput(&r)).ToNot(HaveOccurred())
   124  
   125  			Expect(r.Agents).To(HaveLen(1))
   126  			Expect(r.Agents[0].Agent).To(Equal("rpcutil"))
   127  			Expect(r.Agents[0].Name).To(Equal("rpcutil"))
   128  			Expect(r.Agents[0].Timeout).To(Equal(2))
   129  		})
   130  	})
   131  
   132  	Describe("collective_info action", func() {
   133  		It("Should fetch correct collective info", func() {
   134  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).CollectiveInfo().Do(ctx)
   135  			Expect(err).ToNot(HaveOccurred())
   136  			Expect(res.Stats().OKCount()).To(Equal(1))
   137  
   138  			r := res.AllOutputs()[0]
   139  			Expect(r.Collectives()).To(Equal([]any{"mcollective", "other"}))
   140  			Expect(r.MainCollective()).To(Equal("mcollective"))
   141  		})
   142  	})
   143  
   144  	Describe("daemon_stats action", func() {
   145  		It("Should fetch correct instance stats", func() {
   146  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).DaemonStats().Do(ctx)
   147  			Expect(err).ToNot(HaveOccurred())
   148  			Expect(res.Stats().OKCount()).To(Equal(1))
   149  
   150  			r := res.AllOutputs()[0]
   151  
   152  			Expect(r.Agents()).To(Equal([]any{"rpcutil"}))
   153  			Expect(r.Version()).To(Equal(build.Version))
   154  			path, _ := filepath.Abs("testdata/server.conf")
   155  			Expect(r.Configfile()).To(Equal(path))
   156  		})
   157  	})
   158  
   159  	Describe("get_config_item action", func() {
   160  		It("Should fetch correct item", func() {
   161  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).GetConfigItem("classesfile").Do(ctx)
   162  			Expect(err).ToNot(HaveOccurred())
   163  			Expect(res.Stats().OKCount()).To(Equal(1))
   164  
   165  			r := res.AllOutputs()[0]
   166  			Expect(r.Item()).To(Equal("classesfile"))
   167  			Expect(r.Value()).To(Equal("testdata/classes.txt"))
   168  		})
   169  	})
   170  
   171  	Describe("get_data action", func() {
   172  		It("Should get the right data", func() {
   173  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).GetData("choria").Do(ctx)
   174  			Expect(err).ToNot(HaveOccurred())
   175  			Expect(res.Stats().OKCount()).To(Equal(1))
   176  
   177  			r := res.AllOutputs()[0].HashMap()
   178  
   179  			Expect(r).To(HaveKeyWithValue("classes", []any{"one", "three", "two"}))
   180  			Expect(r).To(HaveKeyWithValue("classes_count", float64(3)))
   181  			Expect(r).To(HaveKeyWithValue("connected_broker", "nats://localhost:4222"))
   182  		})
   183  	})
   184  
   185  	Describe("get_fact", func() {
   186  		It("Should get the right value", func() {
   187  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).GetFact("struct.foo").Do(ctx)
   188  			Expect(err).ToNot(HaveOccurred())
   189  			Expect(res.Stats().OKCount()).To(Equal(1))
   190  
   191  			r := res.AllOutputs()[0]
   192  			Expect(r.Fact()).To(Equal("struct.foo"))
   193  			Expect(r.Value()).To(Equal("bar"))
   194  		})
   195  	})
   196  
   197  	Describe("get_facts", func() {
   198  		It("Should get the right value", func() {
   199  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).GetFacts("struct.foo,bool").Do(ctx)
   200  			Expect(err).ToNot(HaveOccurred())
   201  			Expect(res.Stats().OKCount()).To(Equal(1))
   202  
   203  			r := res.AllOutputs()[0].Values()
   204  			Expect(r).To(HaveKeyWithValue("struct.foo", any("bar")))
   205  			Expect(r).To(HaveKeyWithValue("bool", any(false)))
   206  		})
   207  	})
   208  
   209  	Describe("inventory action", func() {
   210  		It("Should retrieve the correct info", func() {
   211  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).Inventory().Do(ctx)
   212  			Expect(err).ToNot(HaveOccurred())
   213  			Expect(res.Stats().OKCount()).To(Equal(1))
   214  
   215  			r := res.AllOutputs()[0]
   216  			Expect(r.Agents()).To(Equal([]any{"rpcutil"}))
   217  			Expect(r.Classes()).To(Equal([]any{"one", "three", "two"}))
   218  			Expect(r.Collectives()).To(Equal([]any{"mcollective", "other"}))
   219  			Expect(r.MainCollective()).To(Equal("mcollective"))
   220  			Expect(r.DataPlugins()).To(Equal([]any{"choria", "scout"}))
   221  			fj, err := json.Marshal(r.Facts())
   222  			Expect(err).ToNot(HaveOccurred())
   223  			Expect(fj).To(MatchJSON(`{"bool":false,"float":1.1,"int":1,"string":"hello world","struct":{"foo":"bar"}}`))
   224  			Expect(r.Version()).To(Equal(build.Version))
   225  		})
   226  	})
   227  
   228  	Describe("ping action", func() {
   229  		It("Should do the correct pong", func() {
   230  			res, err := rpcutilClient.OptionTargets([]string{"localhost"}).Ping().Do(ctx)
   231  			Expect(err).ToNot(HaveOccurred())
   232  			Expect(res.Stats().OKCount()).To(Equal(1))
   233  
   234  			r := res.AllOutputs()[0]
   235  			Expect(err).ToNot(HaveOccurred())
   236  			Expect(r.Pong()).To(BeNumerically("==", time.Now().Unix(), 1))
   237  		})
   238  	})
   239  })