• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

trento-project / agent / 22064031548

16 Feb 2026 01:07PM UTC coverage: 75.429%. First build
22064031548

Pull #548

github

arbulu89
Import and copy operators code from workbench
Pull Request #548: Import and copy operators code from workbench

1917 of 2247 new or added lines in 18 files covered. (85.31%)

6950 of 9214 relevant lines covered (75.43%)

16.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.24
/internal/operations/operator/saptunechangesolution_v1.go
1
package operator
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "fmt"
7

8
        "github.com/trento-project/agent/internal/core/saptune"
9
        "github.com/trento-project/agent/pkg/utils"
10
)
11

12
const SaptuneChangeSolutionOperatorName = "saptunechangesolution"
13

14
type SaptuneChangeSolutionOption Option[SaptuneChangeSolution]
15

16
// SaptuneChangeSolution is an operator responsible for changing a saptune solution.
17
//
18
// It requires the same kind of argument needed for SaptuneApplySolution: a map containing a key named "solution".
19
//
20
// # Execution Phases
21
//
22
// - PLAN:
23
//   Same as SaptuneApplySolutionOption.
24
//
25
// - COMMIT:
26
//   If there is no other solution already applied, an error is raised,
27
//   effectively allowing a transition from a solution to another but not from no solution to some solution.
28
//          If otherwise there is a solution applied that is not the currently applied one the saptune command to change the
29
//   solution will be executed.
30
//
31
// - VERIFY:
32
//   The operator verifies whether the solution has been correctly changed to the requested one.
33
//   If not, an error is raised.
34
//
35
//   On success, the current state of the applied solution is collected as the "after" diff.
36
//
37
// - ROLLBACK:
38
//   If an error occurs during the COMMIT or VERIFY phase, the saptune solution is changed back to the initially
39
//   applied one.
40

41
type SaptuneChangeSolution struct {
42
        baseOperator
43
        saptune         saptune.Saptune
44
        parsedArguments *saptuneSolutionArguments
45
}
46

47
func WithSaptuneClientChange(saptuneClient saptune.Saptune) SaptuneChangeSolutionOption {
11✔
48
        return func(o *SaptuneChangeSolution) {
22✔
49
                o.saptune = saptuneClient
11✔
50
        }
11✔
51
}
52

53
func NewSaptuneChangeSolution(
54
        arguments Arguments,
55
        operationID string,
56
        options Options[SaptuneChangeSolution],
57
) *Executor {
13✔
58
        saptuneChange := &SaptuneChangeSolution{
13✔
59
                baseOperator: newBaseOperator(
13✔
60
                        SaptuneChangeSolutionOperatorName,
13✔
61
                        operationID,
13✔
62
                        arguments,
13✔
63
                        options.BaseOperatorOptions...,
13✔
64
                ),
13✔
65
        }
13✔
66

13✔
67
        saptuneChange.saptune = saptune.NewSaptuneClient(
13✔
68
                utils.Executor{},
13✔
69
                saptuneChange.logger,
13✔
70
        )
13✔
71

13✔
72
        for _, opt := range options.OperatorOptions {
24✔
73
                opt(saptuneChange)
11✔
74
        }
11✔
75

76
        return &Executor{
13✔
77
                phaser:      saptuneChange,
13✔
78
                operationID: operationID,
13✔
79
                logger:      saptuneChange.logger,
13✔
80
        }
13✔
81
}
82

83
func (sc *SaptuneChangeSolution) plan(ctx context.Context) (bool, error) {
13✔
84
        opArguments, err := parseSaptuneSolutionArguments(sc.arguments)
13✔
85
        if err != nil {
15✔
86
                return false, err
2✔
87
        }
2✔
88
        sc.parsedArguments = opArguments
11✔
89

11✔
90
        if err = sc.saptune.CheckVersionSupport(ctx); err != nil {
12✔
91
                return false, err
1✔
92
        }
1✔
93

94
        initiallyAppliedSolution, err := sc.saptune.GetAppliedSolution(ctx)
10✔
95
        if err != nil {
11✔
96
                return false, err
1✔
97
        }
1✔
98

99
        sc.resources[beforeDiffField] = initiallyAppliedSolution
9✔
100

9✔
101
        if sc.parsedArguments.solution == initiallyAppliedSolution {
10✔
102
                sc.logger.Info("solution is already applied. Nothing to change, skipping operation",
1✔
103
                        "solution", sc.parsedArguments.solution)
1✔
104
                sc.resources[afterDiffField] = initiallyAppliedSolution
1✔
105
                return true, nil
1✔
106
        }
1✔
107

108
        return false, nil
8✔
109
}
110

111
func (sc *SaptuneChangeSolution) commit(ctx context.Context) error {
8✔
112
        initiallyAppliedSolution, _ := sc.resources[beforeDiffField].(string)
8✔
113

8✔
114
        if initiallyAppliedSolution == "" {
9✔
115
                return fmt.Errorf(
1✔
116
                        "cannot change solution to %s because no solution is currently applied",
1✔
117
                        sc.parsedArguments.solution,
1✔
118
                )
1✔
119
        }
1✔
120

121
        return sc.saptune.ChangeSolution(ctx, sc.parsedArguments.solution)
7✔
122
}
123

124
func (sc *SaptuneChangeSolution) verify(ctx context.Context) error {
5✔
125
        initiallyAppliedSolution, _ := sc.resources[beforeDiffField].(string)
5✔
126

5✔
127
        if sc.parsedArguments.solution == initiallyAppliedSolution {
5✔
NEW
128
                sc.resources[afterDiffField] = initiallyAppliedSolution
×
NEW
129
                return nil
×
NEW
130
        }
×
131

132
        appliedSolution, err := sc.saptune.GetAppliedSolution(ctx)
5✔
133
        if err != nil {
7✔
134
                return err
2✔
135
        }
2✔
136

137
        if appliedSolution != sc.parsedArguments.solution {
5✔
138
                return fmt.Errorf(
2✔
139
                        "verify saptune apply failing, the solution %s was not applied in commit phase",
2✔
140
                        sc.parsedArguments.solution,
2✔
141
                )
2✔
142
        }
2✔
143
        sc.resources[afterDiffField] = appliedSolution
1✔
144
        return nil
1✔
145
}
146

147
func (sc *SaptuneChangeSolution) rollback(ctx context.Context) error {
7✔
148
        initiallyAppliedSolution, _ := sc.resources[beforeDiffField].(string)
7✔
149

7✔
150
        if initiallyAppliedSolution == "" {
8✔
151
                return nil
1✔
152
        }
1✔
153

154
        sc.logger.Info("Changing solution to the initially applied one",
6✔
155
                "appliedSolution", initiallyAppliedSolution)
6✔
156
        return sc.saptune.ChangeSolution(ctx, initiallyAppliedSolution)
6✔
157
}
158

159
//        operationDiff needs to be refactored, ignoring duplication issues for now
160
//
161
// nolint: dupl
162
func (sc *SaptuneChangeSolution) operationDiff(_ context.Context) map[string]any {
2✔
163
        diff := make(map[string]any)
2✔
164

2✔
165
        beforeSolution, ok := sc.resources[beforeDiffField].(string)
2✔
166
        if !ok {
2✔
NEW
167
                panic(fmt.Sprintf("invalid beforeSolution value: cannot parse '%s' to string",
×
NEW
168
                        sc.resources[beforeDiffField]))
×
169
        }
170

171
        afterSolution, ok := sc.resources[afterDiffField].(string)
2✔
172
        if !ok {
2✔
NEW
173
                panic(fmt.Sprintf("invalid afterSolution value: cannot parse '%s' to string",
×
NEW
174
                        sc.resources[afterDiffField]))
×
175
        }
176

177
        beforeDiffOutput := saptuneOperationDiffOutput{
2✔
178
                Solution: beforeSolution,
2✔
179
        }
2✔
180
        before, err := json.Marshal(beforeDiffOutput)
2✔
181
        if err != nil {
2✔
NEW
182
                panic(fmt.Sprintf("error marshalling before diff output: %v", err))
×
183
        }
184
        diff[beforeDiffField] = string(before)
2✔
185

2✔
186
        afterDiffOutput := saptuneOperationDiffOutput{
2✔
187
                Solution: afterSolution,
2✔
188
        }
2✔
189
        after, err := json.Marshal(afterDiffOutput)
2✔
190
        if err != nil {
2✔
NEW
191
                panic(fmt.Sprintf("error marshalling after diff output: %v", err))
×
192
        }
193
        diff[afterDiffField] = string(after)
2✔
194

2✔
195
        return diff
2✔
196
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc