package admin import ( "context" "crypto/rand" "fmt" "git.wamblee.org/converge/pkg/comms" "git.wamblee.org/converge/pkg/models" "git.wamblee.org/converge/pkg/testsupport" "github.com/stretchr/testify/suite" "io" "net/http" "strings" "testing" "time" ) // test cases // // Agent only: verify state, verify agentregistration message // - Connect single agent // - Connect agent, connect second agent with duplicate id // -> new id taken out // - Connect more than 100 agents with the same id // -> 101th agents gets error // // Client connected to agent: Verify clientConnection and agentCOnnection, verify state, verify clientInfo message. // - Connect agent + connect client with mmtching id // - Connect agent + connect client with wrong id // // Overall: // - Connect agent, connect 2 clients // - Connect multiple agents and clients type AdminTestSuite struct { suite.Suite ctx context.Context cancelFunc context.CancelFunc pprofServer *http.Server admin *Admin hostKey []byte } func (s *AdminTestSuite) createPipe() (io.ReadWriteCloser, io.ReadWriteCloser) { bitpipe := testsupport.NewInmemoryConnection(s.ctx, "inmemory", 10) return bitpipe.Front(), bitpipe.Back() } func (s *AdminTestSuite) SetupSuite() { s.pprofServer = testsupport.StartPprof("") } func (s *AdminTestSuite) TearDownSuite() { testsupport.StopPprof(s.ctx, s.pprofServer) } func (s *AdminTestSuite) SetupTest() { ctx, cancelFunc := testsupport.CreateTestContext(context.Background(), 10*time.Second) s.ctx = ctx s.cancelFunc = cancelFunc s.admin = NewAdmin() s.hostKey = make([]byte, 100) s.NotNil(rand.Read(s.hostKey)) } func (suite *AdminTestSuite) TearDownTest() { } func TestAdminTestSuite(t *testing.T) { suite.Run(t, &AdminTestSuite{}) } type AddAgentResult struct { agentConn *agentConnection err error } type AgentRegisterResult struct { registration comms.AgentRegistration err error } func (s *AdminTestSuite) agentRegisters(requestedPublicId, assignedPublicId string) (AddAgentResult, AgentRegisterResult) { agentRW, serverRW := s.createPipe() res := testsupport.RunAndWait( &s.Suite, func() any { agentConn, err := s.addAgent(requestedPublicId, assignedPublicId, serverRW) return AddAgentResult{ agentConn: agentConn, err: err, } }, func() any { res := s.agentRegistration(assignedPublicId, agentRW) if assignedPublicId != "" { s.Nil(res.err) s.True(res.registration.Ok) s.Equal(s.hostKey, res.registration.HostPrivateKey) } return res }) return res[0].(AddAgentResult), res[1].(AgentRegisterResult) } func (s *AdminTestSuite) Test_AgentRegisters() { res, _ := s.agentRegisters("abc", "abc") s.Nil(res.err) agentConn := res.agentConn state := s.admin.CreateNotifification() s.Equal(1, len(state.Agents)) s.Equal(0, len(state.Clients)) s.Equal(agentConn.Info, state.Agents[agentConn.Info.Guid]) } func (s *AdminTestSuite) Test_ManyAgentsRegister() { N := 10 agentRegistrations := make([]testsupport.TestFunction, N) for i := range N { publicId := fmt.Sprintf("abc%d", i) agentRegistrations[i] = func() any { res, _ := s.agentRegisters(publicId, publicId) s.Nil(res.err) return res.agentConn } } res := testsupport.RunAndWait( &s.Suite, agentRegistrations...) state := s.admin.CreateNotifification() s.Equal(len(res), len(state.Agents)) s.Equal(0, len(state.Clients)) for _, entry := range res { agentConn := entry.(*agentConnection) s.Equal(agentConn.Info, state.Agents[agentConn.Info.Guid]) } } func (s *AdminTestSuite) Test_agentDuplicateId() { res, _ := s.agentRegisters("abc", "abc") s.Nil(res.err) for i := range 100 { res, _ = s.agentRegisters("abc", fmt.Sprintf("abc-%d", i)) s.Nil(res.err) } res, agentSideResult := s.agentRegisters("abc", "") s.NotNil(res.err) // verify it is the correct error an dnot an id mismatch. s.True(strings.Contains(res.err.Error(), "could not allocate a new unique id")) s.False(agentSideResult.registration.Ok) } func (s *AdminTestSuite) agentRegistration(expectedPublicId string, agentRW io.ReadWriteCloser) AgentRegisterResult { // verify registration message received agentRegistration, err := comms.ReceiveRegistrationMessage(agentRW) if err != nil { return AgentRegisterResult{err: err} } commChannel, err := comms.NewCommChannel(comms.Agent, agentRW) if err != nil { return AgentRegisterResult{registration: agentRegistration, err: err} } s.NotNil(commChannel) return AgentRegisterResult{registration: agentRegistration, err: nil} } func (s *AdminTestSuite) addAgent(publicId string, assignedPublicId string, serverRW io.ReadWriteCloser) (*agentConnection, error) { agentConn, err := s.admin.AddAgent( s.hostKey, models.RendezVousId(publicId), comms.EnvironmentInfo{}, serverRW) if err != nil { return nil, err } s.Equal(assignedPublicId, string(agentConn.Info.PublicId)) return agentConn, nil }