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

mendersoftware / mender-server / 1622978334

13 Jan 2025 03:51PM UTC coverage: 72.802% (-3.8%) from 76.608%
1622978334

Pull #300

gitlab-ci

alfrunes
fix: Deployment device count should not exceed max devices

Added a condition to skip deployments when the device count reaches max
devices.

Changelog: Title
Ticket: MEN-7847
Signed-off-by: Alf-Rune Siqveland <alf.rune@northern.tech>
Pull Request #300: fix: Deployment device count should not exceed max devices

4251 of 6164 branches covered (68.96%)

Branch coverage included in aggregate %.

0 of 18 new or added lines in 1 file covered. (0.0%)

2544 existing lines in 83 files now uncovered.

42741 of 58384 relevant lines covered (73.21%)

21.49 hits per line

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

0.0
/backend/pkg/mongo/doc/ops.go
1
// Copyright 2023 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 doc
16

17
import (
18
        "fmt"
19
        "reflect"
20
        "sort"
21

22
        "go.mongodb.org/mongo-driver/bson"
23
)
24

25
const (
26
        // PermutationThreshold limits the complexity of Unwound maps to the
27
        // given array length.
28
        PermutationThreshold = 1024
29
)
30

31
var (
32
        // ErrPermutations is returned if the map contains arrays with a combined
33
        // number of permutations than the threshold.
34
        ErrPermutations = fmt.Errorf(
35
                "object complexity (array permutations) exceeded threshold")
36
)
37

38
// item is an internally used struct to organize the output in UnwindMap
39
type item struct {
40
        Key   string
41
        Value reflect.Value
42
}
43

44
// UnwindMap takes a string map and perform mongodb $unwind aggregation operation
45
// on all array entries.
46
// Don't return a map - but a sorted list of tuples; mongo indices are sensitive
47
// to order.
48
// Example:
49
//
50
//        {"foo": ["1", "2"], "bar": "3"} becomes
51
//        [ {{"foo", "1", "bar", "3"}}, {{"foo": "2", "bar": "3"}} ]
52
func UnwindMap(
53
        in interface{},
UNCOV
54
) ([]bson.D, error) {
×
UNCOV
55
        // returned bloated map
×
UNCOV
56
        var unwoundMap []bson.D
×
UNCOV
57
        // permutations and cumulative sum of permutations
×
UNCOV
58
        var permutations int64 = 1
×
UNCOV
59

×
UNCOV
60
        inVal := reflect.ValueOf(in)
×
UNCOV
61
        if inVal.Kind() != reflect.Map {
×
62
                return nil, fmt.Errorf(
×
63
                        "invalid argument type: %s != map[string]interface{}",
×
64
                        inVal.Kind().String())
×
65
        }
×
UNCOV
66
        mapLen := inVal.Len()
×
UNCOV
67
        orderedMap := make([]item, mapLen)
×
UNCOV
68

×
UNCOV
69
        // Compute number of permutations and initialize ordered map.
×
UNCOV
70
        var i int
×
UNCOV
71
        keys := inVal.MapKeys()
×
UNCOV
72
        for _, key := range keys {
×
UNCOV
73
                var keyStr string
×
UNCOV
74
                var ok bool
×
UNCOV
75
                value := inVal.MapIndex(key)
×
UNCOV
76
                if key.Kind() == reflect.Interface {
×
77
                        key = key.Elem()
×
78
                }
×
UNCOV
79
                if value.Kind() == reflect.Interface {
×
UNCOV
80
                        value = value.Elem()
×
UNCOV
81
                }
×
UNCOV
82
                if keyStr, ok = key.Interface().(string); !ok {
×
83
                        return nil, fmt.Errorf("invalid argument type: "+
×
84
                                "%s != map[string]interface{}", inVal.Kind())
×
85
                }
×
86

UNCOV
87
                switch value.Kind() {
×
UNCOV
88
                case reflect.Slice, reflect.Array:
×
UNCOV
89
                        orderedMap[i] = item{
×
UNCOV
90
                                Key: keyStr,
×
UNCOV
91
                        }
×
UNCOV
92
                        prevPermutations := permutations
×
UNCOV
93
                        permutations = permutations * int64(value.Len())
×
UNCOV
94

×
UNCOV
95
                        // Check with constraint or overflow
×
UNCOV
96
                        if permutations > PermutationThreshold ||
×
UNCOV
97
                                permutations < prevPermutations {
×
98
                                return nil, ErrPermutations
×
99
                        }
×
100

UNCOV
101
                case reflect.String:
×
UNCOV
102
                        orderedMap[i] = item{
×
UNCOV
103
                                Key: keyStr,
×
UNCOV
104
                        }
×
105
                default:
×
106
                        return nil, fmt.Errorf(
×
107
                                "cannot unwind entry %s of type: %s",
×
108
                                key, value.Kind().String())
×
109
                }
UNCOV
110
                orderedMap[i].Value = value
×
UNCOV
111
                i++
×
112
        }
113

UNCOV
114
        sort.Slice(orderedMap, func(i, j int) bool {
×
UNCOV
115
                return orderedMap[i].Key < orderedMap[j].Key
×
UNCOV
116
        })
×
117

118
        // Allocate returned map array
UNCOV
119
        unwoundMap = make([]bson.D, permutations)
×
UNCOV
120

×
UNCOV
121
        // Fill in the map entries
×
UNCOV
122
        for k := int64(0); k < permutations; k++ {
×
UNCOV
123
                var tmpPerm int64 = 1
×
UNCOV
124
                unwoundMap[k] = make(bson.D, mapLen)
×
UNCOV
125
                for i, item := range orderedMap {
×
UNCOV
126
                        unwoundMap[k][i].Key = item.Key
×
UNCOV
127
                        itemKind := item.Value.Kind()
×
UNCOV
128
                        if itemKind == reflect.Slice ||
×
UNCOV
129
                                itemKind == reflect.Array {
×
UNCOV
130

×
UNCOV
131
                                // Compute index
×
UNCOV
132
                                // - think of it as counting using array
×
UNCOV
133
                                //   length as base
×
UNCOV
134
                                itemLen := item.Value.Len()
×
UNCOV
135
                                idx := (k / tmpPerm) % int64(itemLen)
×
UNCOV
136

×
UNCOV
137
                                unwoundMap[k][i].Value = item.Value.
×
UNCOV
138
                                        Index(int(idx)).Interface()
×
UNCOV
139

×
UNCOV
140
                                // Update cumulative permutations
×
UNCOV
141
                                tmpPerm *= int64(itemLen)
×
UNCOV
142
                        } else {
×
UNCOV
143
                                unwoundMap[k][i].Value = item.Value.Interface()
×
UNCOV
144
                        }
×
145
                }
146
        }
UNCOV
147
        return unwoundMap, nil
×
148
}
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