diff --git a/Makefile b/Makefile index 306c10a6..6ea903dc 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ INSTALL_WHAT:=$(patsubst %, install_%, $(WHAT)) GENERATE_DIRS := ./apricot ./coconut/cmd ./common/runtype ./common/system ./core ./core/integration/ccdb ./core/integration/dcs ./core/integration/ddsched ./core/integration/kafka ./core/integration/odc ./executor ./walnut ./core/integration/trg ./core/integration/bookkeeping SRC_DIRS := ./apricot ./cmd/* ./core ./coconut ./executor ./common ./configuration ./occ/peanut ./walnut TEST_DIRS := ./configuration/cfgbackend -GO_TEST_DIRS := ./core/repos +GO_TEST_DIRS := ./core/repos ./core/integration/dcs # Use linker flags to provide version/build settings to the target PROD :=-X=$(REPOPATH)/common/product @@ -148,18 +148,18 @@ endif done test: - @echo -e "[Ginkgo] \033[1;33mgo test -v --race\033[0m $(TEST_DIRS)\033[0m" - @$(BUILD_FLAGS) go test -v --race $(TEST_DIRS) -ginkgo.show-node-events + @echo -e "[Ginkgo] \033[1;33mgo test -v\033[0m $(TEST_DIRS)\033[0m" + @$(BUILD_FLAGS) go test -v $(TEST_DIRS) -ginkgo.show-node-events - @echo -e "\n[gotest] \033[1;33mgo test -v --race\033[0m $(GO_TEST_DIRS)\033[0m" - @$(BUILD_FLAGS) go test -v --race $(GO_TEST_DIRS) + @echo -e "\n[gotest] \033[1;33mgo test -v\033[0m $(GO_TEST_DIRS)\033[0m" + @$(BUILD_FLAGS) go test -v $(GO_TEST_DIRS) debugtest: - @echo -e "[Ginkgo] \033[1;33mgo test -v --race\033[0m $(TEST_DIRS)\033[0m" - @$(BUILD_FLAGS) go test -v --race $(TEST_DIRS) -ginkgo.v -ginkgo.trace -ginkgo.show-node-events + @echo -e "[Ginkgo] \033[1;33mgo test -v\033[0m $(TEST_DIRS)\033[0m" + @$(BUILD_FLAGS) go test -v $(TEST_DIRS) -ginkgo.v -ginkgo.trace -ginkgo.show-node-events - @echo -e "\n[gotest] \033[1;33mgo test -v --race\033[0m $(GO_TEST_DIRS)\033[0m" - @$(BUILD_FLAGS) go test -v --race $(GO_TEST_DIRS) + @echo -e "\n[gotest] \033[1;33mgo test -v\033[0m $(GO_TEST_DIRS)\033[0m" + @$(BUILD_FLAGS) go test -v $(GO_TEST_DIRS) vet: go vet $(SRC_DIRS) diff --git a/core/integration/dcs/plugin.go b/core/integration/dcs/plugin.go index bca929a6..a6a1578c 100644 --- a/core/integration/dcs/plugin.go +++ b/core/integration/dcs/plugin.go @@ -199,6 +199,16 @@ func (p *Plugin) updateLastKnownDetectorStates(detectorMatrix []*dcspb.DetectorI if _, ok := p.detectorMap[dcsDet]; !ok { p.detectorMap[dcsDet] = detInfo } else { + // If we're getting a PFR or SOR availability information within the State field of an incoming STATE_CHANGE_EVENT, + // before processing it as any other state change, we need to update the availability fields + if detInfo.State == dcspb.DetectorState_PFR_AVAILABLE || detInfo.State == dcspb.DetectorState_PFR_UNAVAILABLE { + p.detectorMap[dcsDet].PfrAvailability = detInfo.State + } + if detInfo.State == dcspb.DetectorState_SOR_AVAILABLE || detInfo.State == dcspb.DetectorState_SOR_UNAVAILABLE { + p.detectorMap[dcsDet].SorAvailability = detInfo.State + } + + // if we're getting a STATE_CHANGE event with any non-null state if detInfo.State != dcspb.DetectorState_NULL_STATE { p.detectorMap[dcsDet].State = detInfo.State timestamp, err := time.Parse(DCS_TIME_FORMAT, detInfo.Timestamp) diff --git a/core/integration/dcs/structs.go b/core/integration/dcs/structs.go index 324cb98d..849c7b48 100644 --- a/core/integration/dcs/structs.go +++ b/core/integration/dcs/structs.go @@ -1,7 +1,7 @@ /* * === This file is part of ALICE O² === * - * Copyright 2021-2023 CERN and copyright holders of ALICE O². + * Copyright 2021-2024 CERN and copyright holders of ALICE O². * Author: Teo Mrnjavac * * This program is free software: you can redistribute it and/or modify @@ -89,6 +89,10 @@ func (dsm DCSDetectorOpAvailabilityMap) makeDetectorsByStateMap() map[dcspb.Dete func (dsm DCSDetectorOpAvailabilityMap) compatibleWithDCSOperation(conditionState dcspb.DetectorState) (bool, error) { detectorsByState := dsm.makeDetectorsByStateMap() + if len(detectorsByState) == 0 { + return true, fmt.Errorf("no detectors provided") + } + detectorsInConditionState, thereAreDetectorsInConditionState := detectorsByState[conditionState] detectorsInNullState, thereAreDetectorsInNullState := detectorsByState[dcspb.DetectorState_NULL_STATE] diff --git a/core/integration/dcs/structs_test.go b/core/integration/dcs/structs_test.go new file mode 100644 index 00000000..3843d712 --- /dev/null +++ b/core/integration/dcs/structs_test.go @@ -0,0 +1,195 @@ +/* + * === This file is part of ALICE O² === + * + * Copyright 2024 CERN and copyright holders of ALICE O². + * Author: Teo Mrnjavac + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In applying this license CERN does not waive the privileges and + * immunities granted to it by virtue of its status as an + * Intergovernmental Organization or submit itself to any jurisdiction. + */ + +package dcs + +import ( + "testing" + + dcspb "github.com/AliceO2Group/Control/core/integration/dcs/protos" +) + +func TestDCSDetectorOpAvailabilityMap_compatibleWithDCSOperation(t *testing.T) { + type args struct { + conditionState dcspb.DetectorState + } + tests := []struct { + name string + dsm DCSDetectorOpAvailabilityMap + args args + want bool + wantErr bool + }{ + { + name: "condition=PFR_AVAILABLE/states=[]", + dsm: map[dcspb.Detector]dcspb.DetectorState{}, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: true, + wantErr: true, + }, + { + name: "condition=PFR_AVAILABLE/states=NULL", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_FT0: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_MID: dcspb.DetectorState_NULL_STATE, + }, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: true, + wantErr: true, + }, + { + name: "condition=SOR_AVAILABLE/states=NULL", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_FT0: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_MID: dcspb.DetectorState_NULL_STATE, + }, + args: args{conditionState: dcspb.DetectorState_SOR_AVAILABLE}, + want: true, + wantErr: true, + }, + { + name: "condition=PFR_AVAILABLE/states=NULL,PFR_UNAVAILABLE", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_FT0: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_MID: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_UNAVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: false, + wantErr: true, + }, + { + name: "condition=PFR_AVAILABLE/states=NULL,PFR_AVAILABLE", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_FT0: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_MID: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_AVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: true, + wantErr: true, + }, + { + name: "condition=PFR_AVAILABLE/states=NULL,PFR_AVAILABLE,PFR_UNAVAILABLE", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_FT0: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_MID: dcspb.DetectorState_NULL_STATE, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_HMP: dcspb.DetectorState_PFR_UNAVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: false, + wantErr: true, + }, + { + name: "condition=PFR_AVAILABLE/states=PFR_AVAILABLE,PFR_UNAVAILABLE", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_FT0: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_MID: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_HMP: dcspb.DetectorState_PFR_UNAVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: false, + wantErr: true, + }, + { + name: "condition=SOR_AVAILABLE/states=PFR_AVAILABLE,PFR_UNAVAILABLE", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_FT0: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_MID: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_HMP: dcspb.DetectorState_PFR_UNAVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_SOR_AVAILABLE}, + want: false, + wantErr: true, + }, + { + name: "condition=PFR_AVAILABLE/states=PFR_AVAILABLE,PFR_UNAVAILABLE,DEAD,ERROR,RUN_INHIBIT", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_DEAD, + dcspb.Detector_FT0: dcspb.DetectorState_ERROR, + dcspb.Detector_MID: dcspb.DetectorState_RUN_INHIBIT, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_HMP: dcspb.DetectorState_PFR_UNAVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: false, + wantErr: true, + }, + { + name: "condition=PFR_AVAILABLE/states=PFR_AVAILABLE", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_FT0: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_MID: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_HMP: dcspb.DetectorState_PFR_AVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_PFR_AVAILABLE}, + want: true, + wantErr: false, + }, + { + name: "condition=SOR_AVAILABLE/states=PFR_AVAILABLE", + dsm: map[dcspb.Detector]dcspb.DetectorState{ + dcspb.Detector_CPV: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_FT0: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_MID: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_EMC: dcspb.DetectorState_PFR_AVAILABLE, + dcspb.Detector_HMP: dcspb.DetectorState_PFR_AVAILABLE, + }, + args: args{conditionState: dcspb.DetectorState_SOR_AVAILABLE}, + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.dsm.compatibleWithDCSOperation(tt.args.conditionState) + if (err != nil) != tt.wantErr { + t.Errorf("compatibleWithDCSOperation() error = %v, wantErr %v", err, tt.wantErr) + return + } else if (err != nil) == tt.wantErr { + t.Logf("compatibleWithDCSOperation() error = %v, wantErr %v", err, tt.wantErr) + } + + if got != tt.want { + if err != nil { + t.Errorf("compatibleWithDCSOperation() got = %v, want %v, error = %s", got, tt.want, err.Error()) + } else { + t.Errorf("compatibleWithDCSOperation() got = %v, want %v", got, tt.want) + } + } + }) + } +}