teleport/lib/service/state_test.go
Vitor Enes b749302e2c
Ensure stateOK is reported only when all components have sent updates (#11249)
Fixes #11065.

This commit:
- ensures  that `TeleportReadyEvent` is only produced when all components that send heartbeats (i.e. call [`process.onHeartbeat`](16bf416556/lib/service/service.go (L358-L366))) are ready
- changes `TeleportProcess.registerTeleportReadyEvent` so that it returns a count of these components (let's call it `componentCount`)
- uses `componentCount` to also ensure that `stateOK` is only reported when all the components have sent their heartbeat, thus fixing #11065

Since it seems difficult to know when `TeleportProcess.registerTeleportReadyEvent` should be updated, with the goal of quickly detecting a bug when it's introduced we have that:
1. if `componentCount` is lower than it should, then the service fails to start (due to #11725)
2. if `componentCount` is higher than it should, then an error is logged in function `processState.getStateLocked`.
2022-04-07 12:28:31 +01:00

96 lines
2.5 KiB
Go

// Copyright 2021 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package service
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestProcessStateGetState(t *testing.T) {
t.Parallel()
tests := []struct {
desc string
states map[string]*componentState
totalComponentCount int
want componentStateEnum
}{
{
desc: "no components",
states: map[string]*componentState{},
totalComponentCount: 1,
want: stateStarting,
},
{
desc: "one component in stateOK",
states: map[string]*componentState{
"one": {state: stateOK},
},
totalComponentCount: 1,
want: stateOK,
},
{
desc: "multiple components in stateOK",
states: map[string]*componentState{
"one": {state: stateOK},
"two": {state: stateOK},
"three": {state: stateOK},
},
totalComponentCount: 3,
want: stateOK,
},
{
desc: "multiple components, one is degraded",
states: map[string]*componentState{
"one": {state: stateRecovering},
"two": {state: stateDegraded},
"three": {state: stateOK},
},
totalComponentCount: 3,
want: stateDegraded,
},
{
desc: "multiple components, one is recovering",
states: map[string]*componentState{
"one": {state: stateOK},
"two": {state: stateRecovering},
"three": {state: stateOK},
},
totalComponentCount: 3,
want: stateRecovering,
},
{
desc: "multiple components, one is starting",
states: map[string]*componentState{
"one": {state: stateOK},
"two": {state: stateStarting},
"three": {state: stateOK},
},
totalComponentCount: 3,
want: stateStarting,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
ps := &processState{states: tt.states, totalComponentCount: tt.totalComponentCount}
got := ps.getState()
require.Equal(t, got, tt.want)
})
}
}