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

mendersoftware / reporting / 714559549

pending completion
714559549

Pull #79

gitlab-ci

Fabio Tranchitella
chore: minor improvements to the mapping utility
Pull Request #79: MEN-5598: map inventory attributes to sequential fields

334 of 403 new or added lines in 12 files covered. (82.88%)

4 existing lines in 2 files now uncovered.

1680 of 2118 relevant lines covered (79.32%)

12.64 hits per line

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

95.45
/store/mongo/datastore_mongo.go
1
// Copyright 2022 Northern.tech AS
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 mongo
16

17
import (
18
        "context"
19
        "crypto/tls"
20
        "fmt"
21
        "net/url"
22

23
        "github.com/pkg/errors"
24
        "go.mongodb.org/mongo-driver/bson"
25
        "go.mongodb.org/mongo-driver/mongo"
26
        "go.mongodb.org/mongo-driver/mongo/options"
27
        mopts "go.mongodb.org/mongo-driver/mongo/options"
28

29
        "github.com/mendersoftware/reporting/model"
30
)
31

32
const (
33
        collNameMapping   = "mapping"
34
        keyNameTenantID   = "tenant_id"
35
        indexNameTenantID = "tenant_id_ndx"
36
)
37

38
type MongoStoreConfig struct {
39
        // MongoURL holds the URL to the MongoDB server.
40
        MongoURL *url.URL
41
        // SSL Enables SSL for mongo connections
42
        SSL bool
43
        // SkipVerify controls whether a mongo client verifies the server's
44
        // certificate chain and host name.
45
        SSLSkipVerify bool
46
        // Username holds the user id credential for authenticating with the
47
        // MongoDB server.
48
        Username string
49
        // Password holds the password credential for authenticating with the
50
        // MongoDB server.
51
        Password string
52
        // DbName contains the name of the reporting database.
53
        DbName string
54
}
55

56
// newClient returns a mongo client
57
func newClient(ctx context.Context, config MongoStoreConfig) (*mongo.Client, error) {
14✔
58

14✔
59
        clientOptions := mopts.Client()
14✔
60
        if config.MongoURL == nil {
16✔
61
                return nil, errors.New("mongo: missing URL")
2✔
62
        }
2✔
63
        clientOptions.ApplyURI(config.MongoURL.String())
12✔
64

12✔
65
        if config.Username != "" {
16✔
66
                credentials := mopts.Credential{
4✔
67
                        Username: config.Username,
4✔
68
                }
4✔
69
                if config.Password != "" {
8✔
70
                        credentials.Password = config.Password
4✔
71
                        credentials.PasswordSet = true
4✔
72
                }
4✔
73
                clientOptions.SetAuth(credentials)
4✔
74
        }
75

76
        if config.SSL {
14✔
77
                tlsConfig := &tls.Config{}
2✔
78
                tlsConfig.InsecureSkipVerify = config.SSLSkipVerify
2✔
79
                clientOptions.SetTLSConfig(tlsConfig)
2✔
80
        }
2✔
81

82
        client, err := mongo.Connect(ctx, clientOptions)
12✔
83
        if err != nil {
14✔
84
                return nil, errors.Wrap(err, "mongo: failed to connect with server")
2✔
85
        }
2✔
86

87
        // Validate connection
88
        if err = client.Ping(ctx, nil); err != nil {
16✔
89
                return nil, errors.Wrap(err, "mongo: error reaching mongo server")
6✔
90
        }
6✔
91

92
        return client, nil
4✔
93
}
94

95
// MongoStore is the data storage service
96
type MongoStore struct {
97
        // client holds the reference to the client used to communicate with the
98
        // mongodb server.
99
        client *mongo.Client
100

101
        config MongoStoreConfig
102
}
103

104
// SetupDataStore returns the mongo data store and optionally runs migrations
105
func NewMongoStore(ctx context.Context, config MongoStoreConfig) (*MongoStore, error) {
14✔
106
        dbClient, err := newClient(ctx, config)
14✔
107
        if err != nil {
24✔
108
                return nil, err
10✔
109
        }
10✔
110
        return &MongoStore{
4✔
111
                client: dbClient,
4✔
112
                config: config,
4✔
113
        }, nil
4✔
114
}
115

NEW
116
func (db *MongoStore) Database(ctx context.Context, opt ...*mopts.DatabaseOptions) *mongo.Database {
×
NEW
117
        return db.client.Database(db.config.DbName, opt...)
×
NEW
118
}
×
119

120
// Ping verifies the connection to the database
121
func (db *MongoStore) Ping(ctx context.Context) error {
2✔
122
        res := db.client.
2✔
123
                Database(db.config.DbName).
2✔
124
                RunCommand(ctx, bson.M{"ping": 1})
2✔
125
        return res.Err()
2✔
126
}
2✔
127

128
// Close disconnects the client
129
func (db *MongoStore) Close(ctx context.Context) error {
4✔
130
        err := db.client.Disconnect(ctx)
4✔
131
        return err
4✔
132
}
4✔
133

134
//nolint:unused
135
func (db *MongoStore) DropDatabase(ctx context.Context) error {
8✔
136
        err := db.client.
8✔
137
                Database(db.config.DbName).
8✔
138
                Drop(ctx)
8✔
139
        return err
8✔
140
}
8✔
141

142
// GetMapping returns the mapping
143
func (db *MongoStore) GetMapping(ctx context.Context, tenantID string) (*model.Mapping, error) {
29✔
144
        query := bson.M{
29✔
145
                keyNameTenantID: tenantID,
29✔
146
        }
29✔
147
        res := db.client.
29✔
148
                Database(db.config.DbName).
29✔
149
                Collection(collNameMapping).
29✔
150
                FindOne(ctx, query)
29✔
151

29✔
152
        mapping := &model.Mapping{}
29✔
153
        err := res.Decode(mapping)
29✔
154
        if err == mongo.ErrNoDocuments {
56✔
155
                mapping = &model.Mapping{
27✔
156
                        TenantID:  tenantID,
27✔
157
                        Inventory: []string{},
27✔
158
                }
27✔
159
        } else if err != nil {
29✔
NEW
160
                return nil, errors.Wrap(err, "failed to update and get the mapping")
×
NEW
161
        }
×
162
        return mapping, nil
29✔
163
}
164

165
// UpdateAndGetMapping updates the mapping and returns it
166
func (db *MongoStore) UpdateAndGetMapping(ctx context.Context, tenantID string,
167
        inventory []string) (*model.Mapping, error) {
12✔
168
        inventoryLastField := fmt.Sprintf("inventory.%d", model.MaxMappingInventoryAttributes-1)
12✔
169
        query := bson.M{
12✔
170
                keyNameTenantID: tenantID,
12✔
171
                inventoryLastField: bson.M{
12✔
172
                        "$exists": false,
12✔
173
                },
12✔
174
        }
12✔
175
        update := bson.M{
12✔
176
                "$addToSet": bson.M{
12✔
177
                        "inventory": bson.M{
12✔
178
                                "$each": inventory,
12✔
179
                        },
12✔
180
                },
12✔
181
        }
12✔
182
        upsert := true
12✔
183
        after := options.After
12✔
184
        opts := &mopts.FindOneAndUpdateOptions{
12✔
185
                ReturnDocument: &after,
12✔
186
                Upsert:         &upsert,
12✔
187
        }
12✔
188
        res := db.client.
12✔
189
                Database(db.config.DbName).
12✔
190
                Collection(collNameMapping).
12✔
191
                FindOneAndUpdate(ctx, query, update, opts)
12✔
192

12✔
193
        mapping := &model.Mapping{}
12✔
194
        err := res.Decode(mapping)
12✔
195
        if err != nil {
14✔
196
                return nil, errors.Wrap(err, "failed to update and get the mapping")
2✔
197
        }
2✔
198
        return mapping, nil
10✔
199
}
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

© 2025 Coveralls, Inc