@@ -4,9 +4,11 @@ import (
44 "testing"
55
66 containertypes "github.com/docker/docker/api/types/container"
7+ "github.com/docker/docker/client"
78 "github.com/docker/docker/integration/internal/container"
89 "github.com/docker/docker/integration/internal/network"
910 "github.com/docker/docker/libnetwork/drivers/bridge"
11+ "github.com/docker/docker/testutil"
1012 "github.com/docker/docker/testutil/daemon"
1113 "gotest.tools/v3/assert"
1214 is "gotest.tools/v3/assert/cmp"
@@ -135,3 +137,97 @@ func TestCfgdMACAddrOnRestart(t *testing.T) {
135137 d .Restart (t )
136138 startAndCheck ()
137139}
140+
141+ // Regression test for https://github.com/moby/moby/issues/47228 - check that a
142+ // generated MAC address is not included in the Config section of 'inspect'
143+ // output, but a configured address is.
144+ func TestInspectCfgdMAC (t * testing.T ) {
145+ skip .If (t , testEnv .DaemonInfo .OSType == "windows" )
146+
147+ ctx := setupTest (t )
148+
149+ d := daemon .New (t )
150+ d .StartWithBusybox (ctx , t )
151+ defer d .Stop (t )
152+
153+ testcases := []struct {
154+ name string
155+ desiredMAC string
156+ netName string
157+ ctrWide bool
158+ }{
159+ {
160+ name : "generated address default bridge" ,
161+ netName : "bridge" ,
162+ },
163+ {
164+ name : "configured address default bridge" ,
165+ desiredMAC : "02:42:ac:11:00:42" ,
166+ netName : "bridge" ,
167+ },
168+ {
169+ name : "generated address custom bridge" ,
170+ netName : "testnet" ,
171+ },
172+ {
173+ name : "configured address custom bridge" ,
174+ desiredMAC : "02:42:ac:11:00:42" ,
175+ netName : "testnet" ,
176+ },
177+ {
178+ name : "ctr-wide address default bridge" ,
179+ desiredMAC : "02:42:ac:11:00:42" ,
180+ netName : "bridge" ,
181+ ctrWide : true ,
182+ },
183+ }
184+
185+ for _ , tc := range testcases {
186+ t .Run (tc .name , func (t * testing.T ) {
187+ ctx := testutil .StartSpan (ctx , t )
188+
189+ var copts []client.Opt
190+ if tc .ctrWide {
191+ copts = append (copts , client .WithVersion ("1.43" ))
192+ }
193+ c := d .NewClientT (t , copts ... )
194+ defer c .Close ()
195+
196+ if tc .netName != "bridge" {
197+ const netName = "inspectcfgmac"
198+ network .CreateNoError (ctx , t , c , netName ,
199+ network .WithDriver ("bridge" ),
200+ network .WithOption (bridge .BridgeName , netName ))
201+ defer network .RemoveNoError (ctx , t , c , netName )
202+ }
203+
204+ const ctrName = "ctr"
205+ opts := []func (* container.TestContainerConfig ){
206+ container .WithName (ctrName ),
207+ container .WithCmd ("top" ),
208+ container .WithImage ("busybox:latest" ),
209+ }
210+ // Don't specify the network name for the bridge network, because that
211+ // exercises a different code path (the network name isn't set until the
212+ // container starts, until then it's "default").
213+ if tc .netName != "bridge" {
214+ opts = append (opts , container .WithNetworkMode (tc .netName ))
215+ }
216+ if tc .desiredMAC != "" {
217+ if tc .ctrWide {
218+ opts = append (opts , container .WithContainerWideMacAddress (tc .desiredMAC ))
219+ } else {
220+ opts = append (opts , container .WithMacAddress (tc .netName , tc .desiredMAC ))
221+ }
222+ }
223+ id := container .Create (ctx , t , c , opts ... )
224+ defer c .ContainerRemove (ctx , id , containertypes.RemoveOptions {
225+ Force : true ,
226+ })
227+
228+ inspect := container .Inspect (ctx , t , c , ctrName )
229+ configMAC := inspect .Config .MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
230+ assert .Check (t , is .DeepEqual (configMAC , tc .desiredMAC ))
231+ })
232+ }
233+ }
0 commit comments