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

mendersoftware / reporting / 715476761

pending completion
715476761

Pull #79

gitlab-ci

Fabio Tranchitella
feat: end-point to list the filterable attributes usage and limits
Pull Request #79: MEN-5598: map inventory attributes to sequential fields

441 of 510 new or added lines in 14 files covered. (86.47%)

13 existing lines in 2 files now uncovered.

1832 of 2225 relevant lines covered (82.34%)

15.09 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) {
4✔
144
        query := bson.M{
4✔
145
                keyNameTenantID: tenantID,
4✔
146
        }
4✔
147
        res := db.client.
4✔
148
                Database(db.config.DbName).
4✔
149
                Collection(collNameMapping).
4✔
150
                FindOne(ctx, query)
4✔
151

4✔
152
        mapping := &model.Mapping{}
4✔
153
        err := res.Decode(mapping)
4✔
154
        if err == mongo.ErrNoDocuments {
5✔
155
                mapping = &model.Mapping{
1✔
156
                        TenantID:  tenantID,
1✔
157
                        Inventory: []string{},
1✔
158
                }
1✔
159
        } else if err != nil {
4✔
NEW
160
                return nil, errors.Wrap(err, "failed to update and get the mapping")
×
NEW
161
        }
×
162
        return mapping, nil
4✔
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) {
14✔
168
        inventoryLastField := fmt.Sprintf("inventory.%d", model.MaxMappingInventoryAttributes-1)
14✔
169
        query := bson.M{
14✔
170
                keyNameTenantID: tenantID,
14✔
171
                inventoryLastField: bson.M{
14✔
172
                        "$exists": false,
14✔
173
                },
14✔
174
        }
14✔
175
        update := bson.M{
14✔
176
                "$addToSet": bson.M{
14✔
177
                        "inventory": bson.M{
14✔
178
                                "$each": inventory,
14✔
179
                        },
14✔
180
                },
14✔
181
        }
14✔
182
        upsert := true
14✔
183
        after := options.After
14✔
184
        opts := &mopts.FindOneAndUpdateOptions{
14✔
185
                ReturnDocument: &after,
14✔
186
                Upsert:         &upsert,
14✔
187
        }
14✔
188
        res := db.client.
14✔
189
                Database(db.config.DbName).
14✔
190
                Collection(collNameMapping).
14✔
191
                FindOneAndUpdate(ctx, query, update, opts)
14✔
192

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