1
1
package ops
2
2
3
3
import (
4
+ "context"
4
5
"testing"
5
6
7
+ "github.com/moby/buildkit/identity"
8
+ "github.com/moby/buildkit/session"
9
+ "github.com/moby/buildkit/solver/pb"
6
10
"github.com/stretchr/testify/require"
7
11
)
8
12
@@ -28,3 +32,128 @@ func TestDedupePaths(t *testing.T) {
28
32
res = dedupePaths ([]string {"/" , "/foo" })
29
33
require .Equal (t , []string {"/" }, res )
30
34
}
35
+
36
+ func TestExecOpCacheMap (t * testing.T ) {
37
+ type testCase struct {
38
+ name string
39
+ op1 , op2 * ExecOp
40
+ xMatch bool
41
+ }
42
+
43
+ newExecOp := func (opts ... func (* ExecOp )) * ExecOp {
44
+ op := & ExecOp {op : & pb.ExecOp {Meta : & pb.Meta {}}}
45
+ for _ , opt := range opts {
46
+ opt (op )
47
+ }
48
+ return op
49
+ }
50
+
51
+ withNewMount := func (p string , cache * pb.CacheOpt ) func (* ExecOp ) {
52
+ return func (op * ExecOp ) {
53
+ m := & pb.Mount {
54
+ Dest : p ,
55
+ Input : pb .InputIndex (op .numInputs ),
56
+ // Generate a new selector for each mount since this should not effect the cache key.
57
+ // This helps exercise that code path.
58
+ Selector : identity .NewID (),
59
+ }
60
+ if cache != nil {
61
+ m .CacheOpt = cache
62
+ m .MountType = pb .MountType_CACHE
63
+ }
64
+ op .op .Mounts = append (op .op .Mounts , m )
65
+ op .numInputs ++
66
+ }
67
+ }
68
+
69
+ withEmptyMounts := func (op * ExecOp ) {
70
+ op .op .Mounts = []* pb.Mount {}
71
+ }
72
+
73
+ testCases := []testCase {
74
+ {name : "empty" , op1 : newExecOp (), op2 : newExecOp (), xMatch : true },
75
+ {
76
+ name : "empty vs with non-nil but empty mounts should match" ,
77
+ op1 : newExecOp (),
78
+ op2 : newExecOp (withEmptyMounts ),
79
+ xMatch : true ,
80
+ },
81
+ {
82
+ name : "both non-nil but empty mounts should match" ,
83
+ op1 : newExecOp (withEmptyMounts ),
84
+ op2 : newExecOp (withEmptyMounts ),
85
+ xMatch : true ,
86
+ },
87
+ {
88
+ name : "non-nil but empty mounts vs with mounts should not match" ,
89
+ op1 : newExecOp (withEmptyMounts ),
90
+ op2 : newExecOp (withNewMount ("/foo" , nil )),
91
+ xMatch : false ,
92
+ },
93
+ {
94
+ name : "mounts to different paths should not match" ,
95
+ op1 : newExecOp (withNewMount ("/foo" , nil )),
96
+ op2 : newExecOp (withNewMount ("/bar" , nil )),
97
+ xMatch : false ,
98
+ },
99
+ {
100
+ name : "mounts to same path should match" ,
101
+ op1 : newExecOp (withNewMount ("/foo" , nil )),
102
+ op2 : newExecOp (withNewMount ("/foo" , nil )),
103
+ xMatch : true ,
104
+ },
105
+ {
106
+ name : "cache mount should not match non-cache mount at same path" ,
107
+ op1 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "someID" })),
108
+ op2 : newExecOp (withNewMount ("/foo" , nil )),
109
+ xMatch : false ,
110
+ },
111
+ {
112
+ name : "different cache id's at the same path should match" ,
113
+ op1 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "someID" })),
114
+ op2 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "someOtherID" })),
115
+ xMatch : true ,
116
+ },
117
+ {
118
+ // This is a special case for default dockerfile cache mounts for backwards compatibility.
119
+ name : "default dockerfile cache mount should not match the same cache mount but with different sharing" ,
120
+ op1 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "/foo" })),
121
+ op2 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "/foo" , Sharing : pb .CacheSharingOpt_LOCKED })),
122
+ xMatch : false ,
123
+ },
124
+ {
125
+ name : "cache mounts with the same ID but different sharing options should match" ,
126
+ op1 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "someID" , Sharing : 0 })),
127
+ op2 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "someID" , Sharing : 1 })),
128
+ xMatch : true ,
129
+ },
130
+ {
131
+ name : "cache mounts with different IDs and different sharing should match at the same path" ,
132
+ op1 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "someID" , Sharing : 0 })),
133
+ op2 : newExecOp (withNewMount ("/foo" , & pb.CacheOpt {ID : "someOtherID" , Sharing : 1 })),
134
+ xMatch : true ,
135
+ },
136
+ }
137
+
138
+ ctx := context .Background ()
139
+ for _ , tc := range testCases {
140
+ tc := tc
141
+ t .Run (tc .name , func (t * testing.T ) {
142
+ t .Parallel ()
143
+
144
+ m1 , ok , err := tc .op1 .CacheMap (ctx , session .NewGroup (t .Name ()), 1 )
145
+ require .NoError (t , err )
146
+ require .True (t , ok )
147
+
148
+ m2 , ok , err := tc .op2 .CacheMap (ctx , session .NewGroup (t .Name ()), 1 )
149
+ require .NoError (t , err )
150
+ require .True (t , ok )
151
+
152
+ if tc .xMatch {
153
+ require .Equal (t , m1 .Digest , m2 .Digest , "\n \n m1: %+v\n m2: %+v" , m1 , m2 )
154
+ } else {
155
+ require .NotEqual (t , m1 .Digest , m2 .Digest , "\n \n m1: %+v\n m2: %+v" , m1 , m2 )
156
+ }
157
+ })
158
+ }
159
+ }
0 commit comments