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

mongodb / mongodb-atlas-cli / 16670223591

01 Aug 2025 08:25AM UTC coverage: 57.953% (-7.1%) from 65.017%
16670223591

Pull #4071

github

fmenezes
chore: remove unit tag from tests
Pull Request #4071: chore: remove unit tag from tests

23613 of 40745 relevant lines covered (57.95%)

2.74 hits per line

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

70.48
/internal/api/executor.go
1
// Copyright 2024 MongoDB Inc
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package api
16

17
import (
18
        "context"
19
        "errors"
20
        "net/http"
21
        "net/http/httputil"
22

23
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config"
24
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log"
25
        storeTransport "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/transport"
26
)
27

28
var (
29
        ErrFailedToAccessToken          = errors.New("failed to get access token")
30
        ErrFailedToConvertToHTTPRequest = errors.New("failed to convert to HTTP request")
31
        ErrFailedToExecuteHTTPRequest   = errors.New("failed to execute HTTP request")
32
        ErrFailedToGetBaseURL           = errors.New("failed to get base url")
33
        ErrFailedToHandleFormat         = errors.New("failed to handle format")
34
        ErrMissingDependency            = errors.New("missing executor dependency")
35
)
36

37
type Executor struct {
38
        commandConverter CommandConverter
39
        httpClient       Doer
40
        formatter        ResponseFormatter
41
        logger           Logger
42
}
43

44
// We're expecting a http client that's authenticated.
45
func NewExecutor(commandConverter CommandConverter, httpClient Doer, formatter ResponseFormatter, logger Logger) (*Executor, error) {
1✔
46
        if commandConverter == nil {
1✔
47
                return nil, errors.Join(ErrMissingDependency, errors.New("commandConverter is nil"))
×
48
        }
×
49

50
        if httpClient == nil {
1✔
51
                return nil, errors.Join(ErrMissingDependency, errors.New("httpClient is nil"))
×
52
        }
×
53

54
        if formatter == nil {
1✔
55
                return nil, errors.Join(ErrMissingDependency, errors.New("formatter is nil"))
×
56
        }
×
57

58
        if logger == nil {
1✔
59
                return nil, errors.Join(ErrMissingDependency, errors.New("logger is nil"))
×
60
        }
×
61

62
        return &Executor{
1✔
63
                commandConverter: commandConverter,
1✔
64
                httpClient:       httpClient,
1✔
65
                formatter:        formatter,
1✔
66
                logger:           logger,
1✔
67
        }, nil
1✔
68
}
69

70
// Executor wired up to use the default profile and static functions on config.
71
func NewDefaultExecutor(formatter ResponseFormatter) (*Executor, error) {
1✔
72
        profile := config.Default()
1✔
73

1✔
74
        client := &http.Client{
1✔
75
                Transport: authenticatedTransport(profile, storeTransport.Default()),
1✔
76
        }
1✔
77

1✔
78
        configWrapper := NewAuthenticatedConfigWrapper(profile)
1✔
79
        commandConverter, err := NewDefaultCommandConverter(configWrapper)
1✔
80
        if err != nil {
1✔
81
                return nil, err
×
82
        }
×
83

84
        return NewExecutor(
1✔
85
                commandConverter,
1✔
86
                client,
1✔
87
                formatter,
1✔
88
                log.Default(),
1✔
89
        )
1✔
90
}
91

92
func (e *Executor) ensureInitialized() {
1✔
93
        if e.commandConverter == nil || e.httpClient == nil {
1✔
94
                // panic because this is developer error, not user error
×
95
                // should never happen
×
96
                panic("the executor was not properly initialized, use the NewExecutor method to initialize this struct")
×
97
        }
98
}
99

100
func (e *Executor) ExecuteCommand(ctx context.Context, commandRequest CommandRequest) (*CommandResponse, error) {
1✔
101
        e.ensureInitialized()
1✔
102

1✔
103
        // Set the content type
1✔
104
        if err := e.SetContentType(&commandRequest); err != nil {
1✔
105
                return nil, err
×
106
        }
×
107

108
        // Convert the request (api command definition + execution context) into a http request
109
        httpRequest, err := e.commandConverter.ConvertToHTTPRequest(commandRequest)
1✔
110
        if err != nil {
1✔
111
                return nil, errors.Join(ErrFailedToBuildHTTPRequest, err)
×
112
        }
×
113

114
        // Set the context, so we can cancel the request
115
        httpRequest = httpRequest.WithContext(ctx)
1✔
116
        e.logRequest(httpRequest)
1✔
117

1✔
118
        // Execute the request
1✔
119
        httpResponse, err := e.httpClient.Do(httpRequest)
1✔
120
        if err != nil {
1✔
121
                return nil, errors.Join(ErrFailedToConvertToHTTPRequest, err)
×
122
        }
×
123

124
        e.logResponse(httpResponse)
1✔
125

1✔
126
        //nolint: mnd // httpResponse.StatusCode >= StatusOK && httpResponse.StatusCode < StatusMultipleChoices makes this code harder to read
1✔
127
        isSuccess := httpResponse.StatusCode >= 200 && httpResponse.StatusCode < 300
1✔
128
        httpCode := httpResponse.StatusCode
1✔
129
        output := httpResponse.Body
1✔
130

1✔
131
        response := CommandResponse{
1✔
132
                IsSuccess: isSuccess,
1✔
133
                HTTPCode:  httpCode,
1✔
134
                Output:    output,
1✔
135
        }
1✔
136

1✔
137
        return &response, nil
1✔
138
}
139

140
func (e *Executor) SetContentType(commandRequest *CommandRequest) error {
1✔
141
        e.ensureInitialized()
1✔
142

1✔
143
        // Update the format if needed
1✔
144
        // For example if the requested format is a go template, change the request format to json
1✔
145
        contentType, err := e.formatter.ContentType(commandRequest.Format)
1✔
146
        if err != nil {
1✔
147
                return errors.Join(ErrFailedToHandleFormat, err)
×
148
        }
×
149
        commandRequest.ContentType = contentType
1✔
150

1✔
151
        return nil
1✔
152
}
153

154
// Log the request if the logger is set to debug
155
// Copied behavior and format used in the SDK: https://github.com/mongodb/atlas-sdk-go/blob/b3fee40e236a8ff2a1f1c160b6984a242136dbe6/admin/client.go#L322
156
func (e *Executor) logRequest(httpRequest *http.Request) {
1✔
157
        if !e.logger.IsDebugLevel() {
2✔
158
                return
1✔
159
        }
1✔
160

161
        dump, err := httputil.DumpRequestOut(httpRequest, true)
×
162
        if err != nil {
×
163
                return
×
164
        }
×
165

166
        _, _ = e.logger.Debugf("\n%s\n", string(dump))
×
167
}
168

169
// Log the response if the logger is set to debug
170
// Copied behavior and format used in the SDK: https://github.com/mongodb/atlas-sdk-go/blob/b3fee40e236a8ff2a1f1c160b6984a242136dbe6/admin/client.go#L335
171
func (e *Executor) logResponse(httpResponse *http.Response) {
1✔
172
        if !e.logger.IsDebugLevel() {
2✔
173
                return
1✔
174
        }
1✔
175

176
        dump, err := httputil.DumpResponse(httpResponse, true)
×
177
        if err != nil {
×
178
                return
×
179
        }
×
180

181
        _, _ = e.logger.Debugf("\n%s\n", string(dump))
×
182
}
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