github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/rkt/api_service_test.go (about)

     1  // Copyright 2015 The rkt Authors
     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 main
    16  
    17  import (
    18  	"io/ioutil"
    19  	"net"
    20  	"os"
    21  	"testing"
    22  
    23  	"github.com/rkt/rkt/api/v1alpha"
    24  	"github.com/rkt/rkt/pkg/log"
    25  )
    26  
    27  func TestFilterPod(t *testing.T) {
    28  	tests := []struct {
    29  		pod    *v1alpha.Pod
    30  		filter *v1alpha.PodFilter
    31  		result bool
    32  	}{
    33  		// Has the status.
    34  		{
    35  			&v1alpha.Pod{
    36  				State: v1alpha.PodState_POD_STATE_RUNNING,
    37  			},
    38  			&v1alpha.PodFilter{
    39  				States: []v1alpha.PodState{v1alpha.PodState_POD_STATE_RUNNING},
    40  			},
    41  			true,
    42  		},
    43  		// Doesn't have the status.
    44  		{
    45  			&v1alpha.Pod{
    46  				State: v1alpha.PodState_POD_STATE_EXITED,
    47  			},
    48  			&v1alpha.PodFilter{
    49  				States: []v1alpha.PodState{v1alpha.PodState_POD_STATE_RUNNING},
    50  			},
    51  			false,
    52  		},
    53  		// Has all app names.
    54  		{
    55  			&v1alpha.Pod{
    56  				Apps: []*v1alpha.App{
    57  					{Name: "app-foo"},
    58  					{Name: "app-bar"},
    59  				},
    60  			},
    61  			&v1alpha.PodFilter{
    62  				AppNames: []string{"app-foo", "app-bar"},
    63  			},
    64  			true,
    65  		},
    66  		// Doesn't have all app name.
    67  		{
    68  			&v1alpha.Pod{
    69  				Apps: []*v1alpha.App{
    70  					{Name: "app-foo"},
    71  					{Name: "app-bar"},
    72  				},
    73  			},
    74  			&v1alpha.PodFilter{
    75  				AppNames: []string{"app-foo", "app-bar", "app-baz"},
    76  			},
    77  			false,
    78  		},
    79  		// Has all network names.
    80  		{
    81  			&v1alpha.Pod{
    82  				Networks: []*v1alpha.Network{
    83  					{Name: "network-foo"},
    84  					{Name: "network-bar"},
    85  				},
    86  			},
    87  			&v1alpha.PodFilter{
    88  				NetworkNames: []string{"network-foo", "network-bar"},
    89  			},
    90  			true,
    91  		},
    92  		// Doesn't have all network names.
    93  		{
    94  			&v1alpha.Pod{
    95  				Networks: []*v1alpha.Network{
    96  					{Name: "network-foo"},
    97  					{Name: "network-bar"},
    98  				},
    99  			},
   100  			&v1alpha.PodFilter{
   101  				NetworkNames: []string{"network-foo", "network-bar", "network-baz"},
   102  			},
   103  			false,
   104  		},
   105  		// Has all annotations.
   106  		{
   107  			&v1alpha.Pod{
   108  				Annotations: []*v1alpha.KeyValue{
   109  					{"annotation-key-foo", "annotation-value-foo"},
   110  					{"annotation-key-bar", "annotation-value-bar"},
   111  				},
   112  			},
   113  			&v1alpha.PodFilter{
   114  				Annotations: []*v1alpha.KeyValue{
   115  					{"annotation-key-foo", "annotation-value-foo"},
   116  					{"annotation-key-bar", "annotation-value-bar"},
   117  				},
   118  			},
   119  			true,
   120  		},
   121  		// Doesn't have all annotation keys.
   122  		{
   123  			&v1alpha.Pod{
   124  				Annotations: []*v1alpha.KeyValue{
   125  					{"annotation-key-foo", "annotation-value-foo"},
   126  					{"annotation-key-bar", "annotation-value-bar"},
   127  				},
   128  			},
   129  			&v1alpha.PodFilter{
   130  				Annotations: []*v1alpha.KeyValue{
   131  					{"annotation-key-foo", "annotation-value-foo"},
   132  					{"annotation-key-bar", "annotation-value-bar"},
   133  					{"annotation-key-baz", "annotation-value-baz"},
   134  				},
   135  			},
   136  			false,
   137  		},
   138  		// Doesn't have all annotation values.
   139  		{
   140  			&v1alpha.Pod{
   141  				Annotations: []*v1alpha.KeyValue{
   142  					{"annotation-key-foo", "annotation-value-foo"},
   143  					{"annotation-key-bar", "annotation-value-bar"},
   144  				},
   145  			},
   146  			&v1alpha.PodFilter{
   147  				Annotations: []*v1alpha.KeyValue{
   148  					{"annotation-key-foo", "annotation-value-foo"},
   149  					{"annotation-key-bar", "annotation-value-baz"},
   150  				},
   151  			},
   152  			false,
   153  		},
   154  		// Doesn't satisfy any filter conditions.
   155  		{
   156  			&v1alpha.Pod{
   157  				Apps:        []*v1alpha.App{{Name: "app-foo"}},
   158  				Networks:    []*v1alpha.Network{{Name: "network-foo"}},
   159  				Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   160  			},
   161  			&v1alpha.PodFilter{
   162  				AppNames:     []string{"app-bar"},
   163  				NetworkNames: []string{"network-bar"},
   164  				Annotations:  []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-bar"}},
   165  			},
   166  			false,
   167  		},
   168  		// Satisfies some filter conditions.
   169  		{
   170  			&v1alpha.Pod{
   171  				Apps:        []*v1alpha.App{{Name: "app-foo"}},
   172  				Networks:    []*v1alpha.Network{{Name: "network-foo"}},
   173  				Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   174  			},
   175  			&v1alpha.PodFilter{
   176  				AppNames:     []string{"app-foo", "app-bar"},
   177  				NetworkNames: []string{"network-bar"},
   178  				Annotations:  []*v1alpha.KeyValue{{"annotation-key-bar", "annotation-value-bar"}},
   179  			},
   180  			false,
   181  		},
   182  		// Satisfies all filter conditions.
   183  		{
   184  			&v1alpha.Pod{
   185  				Apps:        []*v1alpha.App{{Name: "app-foo"}},
   186  				Networks:    []*v1alpha.Network{{Name: "network-foo"}},
   187  				Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   188  			},
   189  			&v1alpha.PodFilter{
   190  				AppNames:     []string{"app-foo"},
   191  				NetworkNames: []string{"network-foo"},
   192  				Annotations:  []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   193  			},
   194  			true,
   195  		},
   196  	}
   197  
   198  	for i, tt := range tests {
   199  		result := satisfiesPodFilter(*tt.pod, *tt.filter)
   200  		if result != tt.result {
   201  			t.Errorf("#%d: got %v, want %v", i, result, tt.result)
   202  		}
   203  	}
   204  }
   205  
   206  func TestFilterPodAny(t *testing.T) {
   207  	tests := []struct {
   208  		pod     *v1alpha.Pod
   209  		filters []*v1alpha.PodFilter
   210  		result  bool
   211  	}{
   212  		// No filters.
   213  		{
   214  			&v1alpha.Pod{
   215  				Apps:     []*v1alpha.App{{Name: "app-foo"}},
   216  				Networks: []*v1alpha.Network{{Name: "network-foo"}},
   217  			},
   218  			nil,
   219  			true,
   220  		},
   221  		// Satisfies all filters.
   222  		{
   223  			&v1alpha.Pod{
   224  				Apps:     []*v1alpha.App{{Name: "app-foo"}},
   225  				Networks: []*v1alpha.Network{{Name: "network-foo"}},
   226  			},
   227  			[]*v1alpha.PodFilter{
   228  				{AppNames: []string{"app-foo"}},
   229  				{NetworkNames: []string{"network-foo"}},
   230  			},
   231  			true,
   232  		},
   233  		// Satisfies any filters.
   234  		{
   235  			&v1alpha.Pod{
   236  				Apps:     []*v1alpha.App{{Name: "app-foo"}},
   237  				Networks: []*v1alpha.Network{{Name: "network-foo"}},
   238  			},
   239  			[]*v1alpha.PodFilter{
   240  				{AppNames: []string{"app-foo"}},
   241  				{NetworkNames: []string{"network-bar"}},
   242  			},
   243  			true,
   244  		},
   245  		// Satisfies none filters.
   246  		{
   247  			&v1alpha.Pod{
   248  				Apps:     []*v1alpha.App{{Name: "app-foo"}},
   249  				Networks: []*v1alpha.Network{{Name: "network-foo"}},
   250  			},
   251  			[]*v1alpha.PodFilter{
   252  				{AppNames: []string{"app-bar"}},
   253  				{NetworkNames: []string{"network-bar"}},
   254  			},
   255  			false,
   256  		},
   257  	}
   258  
   259  	for i, tt := range tests {
   260  		result := satisfiesAnyPodFilters(tt.pod, tt.filters)
   261  		if result != tt.result {
   262  			t.Errorf("#%d: got %v, want %v", i, result, tt.result)
   263  		}
   264  	}
   265  }
   266  
   267  func TestFilterImage(t *testing.T) {
   268  	tests := []struct {
   269  		image  *v1alpha.Image
   270  		filter *v1alpha.ImageFilter
   271  		result bool
   272  	}{
   273  		// Has the id.
   274  		{
   275  			&v1alpha.Image{
   276  				Id: "id-foo",
   277  			},
   278  			&v1alpha.ImageFilter{
   279  				Ids: []string{"id-first", "id-foo", "id-last"},
   280  			},
   281  			true,
   282  		},
   283  		// Doesn't have the id.
   284  		{
   285  			&v1alpha.Image{
   286  				Id: "id-foo",
   287  			},
   288  			&v1alpha.ImageFilter{
   289  				Ids: []string{"id-first", "id-second", "id-last"},
   290  			},
   291  			false,
   292  		},
   293  		// Has the prefix in the name.
   294  		{
   295  			&v1alpha.Image{
   296  				Name: "prefix-foo-foo",
   297  			},
   298  			&v1alpha.ImageFilter{
   299  				Prefixes: []string{"prefix-first", "prefix-foo", "prefix-last"},
   300  			},
   301  			true,
   302  		},
   303  		// Doesn't have the prefix in the name.
   304  		{
   305  			&v1alpha.Image{
   306  				Name: "prefix-foo-foo",
   307  			},
   308  			&v1alpha.ImageFilter{
   309  				Prefixes: []string{"prefix-first", "prefix-second", "prefix-last"},
   310  			},
   311  			false,
   312  		},
   313  		// Has the base name in the name.
   314  		{
   315  			&v1alpha.Image{
   316  				Name: "foo/basename-foo",
   317  			},
   318  			&v1alpha.ImageFilter{
   319  				BaseNames: []string{"basename-first", "basename-foo", "basename-last"},
   320  			},
   321  			true,
   322  		},
   323  		// Doesn't have the base name in the name.
   324  		{
   325  			&v1alpha.Image{
   326  				Name: "foo/basename-foo",
   327  			},
   328  			&v1alpha.ImageFilter{
   329  				BaseNames: []string{"basename-first", "basename-second", "basename-last"},
   330  			},
   331  			false,
   332  		},
   333  		// Has the keyword in the name.
   334  		{
   335  			&v1alpha.Image{
   336  				Name: "foo-keyword-foo-foo",
   337  			},
   338  			&v1alpha.ImageFilter{
   339  				Keywords: []string{"keyword-first", "keyword-foo", "keyword-last"},
   340  			},
   341  			true,
   342  		},
   343  		// Doesn't have the keyword in the name.
   344  		{
   345  			&v1alpha.Image{
   346  				Name: "foo-keyword-foo-foo",
   347  			},
   348  			&v1alpha.ImageFilter{
   349  				Keywords: []string{"keyword-first", "keyword-second", "keyword-last"},
   350  			},
   351  			false,
   352  		},
   353  		// Has all the labels in the manifest.
   354  		{
   355  			&v1alpha.Image{
   356  				Labels: []*v1alpha.KeyValue{
   357  					{"label-key-foo", "label-value-foo"},
   358  					{"label-key-bar", "label-value-bar"},
   359  				},
   360  			},
   361  			&v1alpha.ImageFilter{
   362  				Labels: []*v1alpha.KeyValue{
   363  					{"label-key-foo", "label-value-foo"},
   364  					{"label-key-bar", "label-value-bar"},
   365  				},
   366  			},
   367  			true,
   368  		},
   369  		// Doesn't have all the label keys in the manifest.
   370  		{
   371  			&v1alpha.Image{
   372  				Labels: []*v1alpha.KeyValue{
   373  					{"label-key-foo", "label-value-foo"},
   374  					{"label-key-bar", "label-value-bar"},
   375  				},
   376  			},
   377  			&v1alpha.ImageFilter{
   378  				Labels: []*v1alpha.KeyValue{
   379  					{"label-key-foo", "label-value-foo"},
   380  					{"label-key-bar", "label-value-bar"},
   381  					{"label-key-baz", "label-value-baz"},
   382  				},
   383  			},
   384  			false,
   385  		},
   386  		// Doesn't have all the label values in the manifest.
   387  		{
   388  			&v1alpha.Image{
   389  				Labels: []*v1alpha.KeyValue{
   390  					{"label-key-foo", "label-value-foo"},
   391  					{"label-key-bar", "label-value-bar"},
   392  				},
   393  			},
   394  			&v1alpha.ImageFilter{
   395  				Labels: []*v1alpha.KeyValue{
   396  					{"label-key-foo", "label-value-foo"},
   397  					{"label-key-bar", "label-value-baz"},
   398  				},
   399  			},
   400  			false,
   401  		},
   402  		// Has all the annotation in the manifest.
   403  		{
   404  			&v1alpha.Image{
   405  				Annotations: []*v1alpha.KeyValue{
   406  					{"annotation-key-foo", "annotation-value-foo"},
   407  					{"annotation-key-bar", "annotation-value-bar"},
   408  				},
   409  			},
   410  			&v1alpha.ImageFilter{
   411  				Annotations: []*v1alpha.KeyValue{
   412  					{"annotation-key-foo", "annotation-value-foo"},
   413  					{"annotation-key-bar", "annotation-value-bar"},
   414  				},
   415  			},
   416  			true,
   417  		},
   418  		// Doesn't have all the annotation keys in the manifest.
   419  		{
   420  			&v1alpha.Image{
   421  				Annotations: []*v1alpha.KeyValue{
   422  					{"annotation-key-foo", "annotation-value-foo"},
   423  					{"annotation-key-bar", "annotation-value-bar"},
   424  				},
   425  			},
   426  			&v1alpha.ImageFilter{
   427  				Annotations: []*v1alpha.KeyValue{
   428  					{"annotation-key-foo", "annotation-value-foo"},
   429  					{"annotation-key-bar", "annotation-value-bar"},
   430  					{"annotation-key-baz", "annotation-value-baz"},
   431  				},
   432  			},
   433  			false,
   434  		},
   435  		// Doesn't have all the annotation values in the manifest.
   436  		{
   437  			&v1alpha.Image{
   438  				Annotations: []*v1alpha.KeyValue{
   439  					{"annotation-key-foo", "annotation-value-foo"},
   440  					{"annotation-key-bar", "annotation-value-bar"},
   441  				},
   442  			},
   443  			&v1alpha.ImageFilter{
   444  				Annotations: []*v1alpha.KeyValue{
   445  					{"annotation-key-foo", "annotation-value-foo"},
   446  					{"annotation-key-bar", "annotation-value-baz"},
   447  				},
   448  			},
   449  			false,
   450  		},
   451  		// Satisfies 'imported after'.
   452  		{
   453  			&v1alpha.Image{ImportTimestamp: 1024},
   454  			&v1alpha.ImageFilter{
   455  				ImportedAfter: 1023,
   456  			},
   457  			true,
   458  		},
   459  		// Doesn't satisfy 'imported after'.
   460  		{
   461  			&v1alpha.Image{ImportTimestamp: 1024},
   462  			&v1alpha.ImageFilter{
   463  				ImportedAfter: 1024,
   464  			},
   465  			false,
   466  		},
   467  		// Satisfies 'imported before'.
   468  		{
   469  			&v1alpha.Image{ImportTimestamp: 1024},
   470  			&v1alpha.ImageFilter{
   471  				ImportedBefore: 1025,
   472  			},
   473  			true,
   474  		},
   475  		// Doesn't satisfy 'imported before'.
   476  		{
   477  			&v1alpha.Image{ImportTimestamp: 1024},
   478  			&v1alpha.ImageFilter{
   479  				ImportedBefore: 1024,
   480  			},
   481  			false,
   482  		},
   483  		// Match one of the full names.
   484  		{
   485  			&v1alpha.Image{Name: "foo/basename-foo"},
   486  			&v1alpha.ImageFilter{
   487  				FullNames: []string{"foo/basename-foo", "foo/basename-bar"},
   488  			},
   489  			true,
   490  		},
   491  		// Doesn't match any full names.
   492  		{
   493  			&v1alpha.Image{Name: "foo/basename-foo"},
   494  			&v1alpha.ImageFilter{
   495  				FullNames: []string{"bar/basename-foo", "foo/basename-bar"},
   496  			},
   497  			false,
   498  		},
   499  		// Doesn't satisfy any filter conditions.
   500  		{
   501  			&v1alpha.Image{
   502  				Id:              "id-foo",
   503  				Name:            "prefix-foo-keyword-foo/basename-foo",
   504  				Version:         "1.0",
   505  				ImportTimestamp: 1024,
   506  				Labels:          []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}},
   507  				Annotations:     []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   508  			},
   509  			&v1alpha.ImageFilter{
   510  				Ids:            []string{"id-bar"},
   511  				Prefixes:       []string{"prefix-bar"},
   512  				BaseNames:      []string{"basename-bar"},
   513  				Keywords:       []string{"keyword-bar"},
   514  				Labels:         []*v1alpha.KeyValue{{"label-key-bar", "label-value-bar"}},
   515  				Annotations:    []*v1alpha.KeyValue{{"annotation-key-bar", "annotation-value-bar"}},
   516  				ImportedBefore: 1024,
   517  				ImportedAfter:  1024,
   518  			},
   519  			false,
   520  		},
   521  		// Satisfies some filter conditions.
   522  		{
   523  			&v1alpha.Image{
   524  				Id:              "id-foo",
   525  				Name:            "prefix-foo-keyword-foo/basename-foo",
   526  				Version:         "1.0",
   527  				ImportTimestamp: 1024,
   528  				Labels:          []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}},
   529  				Annotations:     []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   530  			},
   531  			&v1alpha.ImageFilter{
   532  				Ids:            []string{"id-bar", "id-foo"},
   533  				Prefixes:       []string{"prefix-bar"},
   534  				BaseNames:      []string{"basename-bar"},
   535  				Keywords:       []string{"keyword-bar"},
   536  				Labels:         []*v1alpha.KeyValue{{"label-key-bar", "label-value-bar"}},
   537  				Annotations:    []*v1alpha.KeyValue{{"annotation-key-bar", "annotation-value-bar"}},
   538  				ImportedBefore: 1024,
   539  				ImportedAfter:  1024,
   540  			},
   541  			false,
   542  		},
   543  		// Satisfies all filter conditions.
   544  		{
   545  			&v1alpha.Image{
   546  				Id:              "id-foo",
   547  				Name:            "prefix-foo-keyword-foo/basename-foo",
   548  				Version:         "1.0",
   549  				ImportTimestamp: 1024,
   550  				Labels:          []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}},
   551  				Annotations:     []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   552  			},
   553  			&v1alpha.ImageFilter{
   554  				Ids:            []string{"id-bar", "id-foo"},
   555  				Prefixes:       []string{"prefix-bar", "prefix-foo"},
   556  				BaseNames:      []string{"basename-bar", "basename-foo"},
   557  				Keywords:       []string{"keyword-bar", "keyword-foo"},
   558  				Labels:         []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}},
   559  				Annotations:    []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}},
   560  				ImportedBefore: 1025,
   561  				ImportedAfter:  1023,
   562  			},
   563  			true,
   564  		},
   565  	}
   566  
   567  	for i, tt := range tests {
   568  		result := satisfiesImageFilter(*tt.image, *tt.filter)
   569  		if result != tt.result {
   570  			t.Errorf("#%d: got %v, want %v", i, result, tt.result)
   571  		}
   572  	}
   573  }
   574  
   575  func TestFilterImageAny(t *testing.T) {
   576  	tests := []struct {
   577  		image   *v1alpha.Image
   578  		filters []*v1alpha.ImageFilter
   579  		result  bool
   580  	}{
   581  		// No filters.
   582  		{
   583  			&v1alpha.Image{
   584  				Id:   "id-foo",
   585  				Name: "prefix-foo-keyword-foo/basename-foo",
   586  			},
   587  			nil,
   588  			true,
   589  		},
   590  		// Satisfies all filters.
   591  		{
   592  			&v1alpha.Image{
   593  				Id:   "id-foo",
   594  				Name: "prefix-foo-keyword-foo/basename-foo",
   595  			},
   596  			[]*v1alpha.ImageFilter{
   597  				{Ids: []string{"id-foo"}},
   598  				{BaseNames: []string{"basename-foo"}},
   599  			},
   600  			true,
   601  		},
   602  		// Satisfies any filters.
   603  		{
   604  			&v1alpha.Image{
   605  				Id:   "id-foo",
   606  				Name: "prefix-foo-keyword-foo/basename-foo",
   607  			},
   608  			[]*v1alpha.ImageFilter{
   609  				{Ids: []string{"id-foo"}},
   610  				{BaseNames: []string{"basename-bar"}},
   611  			},
   612  			true,
   613  		},
   614  		// Satisfies none filters.
   615  		{
   616  			&v1alpha.Image{
   617  				Id:   "id-foo",
   618  				Name: "prefix-foo-keyword-foo/basename-foo",
   619  			},
   620  			[]*v1alpha.ImageFilter{
   621  				{Ids: []string{"id-bar"}},
   622  				{BaseNames: []string{"basename-bar"}},
   623  			},
   624  			false,
   625  		},
   626  	}
   627  
   628  	for i, tt := range tests {
   629  		result := satisfiesAnyImageFilters(tt.image, tt.filters)
   630  		if result != tt.result {
   631  			t.Errorf("#%d: got %v, want %v", i, result, tt.result)
   632  		}
   633  	}
   634  }
   635  
   636  // Test that we open the correct kinds of sockets
   637  func TestOpenSocket(t *testing.T) {
   638  	stderr = log.New(os.Stderr, "TestOpenSocket", globalFlags.Debug)
   639  	// get a temp unix socket for us to play with
   640  	tempdir, err := ioutil.TempDir("", "TestOpenSocket")
   641  	if err != nil {
   642  		t.Fatal(err)
   643  	}
   644  	defer os.RemoveAll(tempdir)
   645  
   646  	l, err := net.Listen("unix", tempdir+"/sock")
   647  	if err != nil {
   648  		t.Fatal(err)
   649  	}
   650  	defer l.Close()
   651  	lfd, err := l.(*net.UnixListener).File()
   652  	if err != nil {
   653  		t.Fatal(err)
   654  	}
   655  	defer lfd.Close()
   656  
   657  	// Mock out the systemd FD function
   658  	systemdFDs = func(x bool) []*os.File {
   659  		return []*os.File{lfd}
   660  	}
   661  
   662  	// Test that we will open a systemd socket when asked for
   663  	l1, err := openAPISockets()
   664  	if err != nil {
   665  		t.Fatal(err)
   666  	}
   667  	if len(l1) != 1 {
   668  		t.Errorf("expected len(l1) = 1, got %d", len(l1))
   669  	}
   670  
   671  	// Test that we fail when --listen is passed with a systemd socket
   672  	flagAPIServiceListenAddr = "localhost:0"
   673  	_, err = openAPISockets()
   674  	if err == nil {
   675  		t.Error("openAPISockets() did not fail when passed systemd socket and --listen")
   676  	}
   677  
   678  	// Then, disable socket mode and ask it to open a random tcp server port
   679  	systemdFDs = func(x bool) []*os.File {
   680  		return nil
   681  	}
   682  
   683  	l2, err := openAPISockets()
   684  	if err != nil {
   685  		t.Fatal("failed to open socket", err)
   686  	}
   687  
   688  	for _, ll := range l2 {
   689  		defer ll.Close()
   690  	}
   691  
   692  	if len(l2) != 1 {
   693  		t.Errorf("expected len(l2) == 1, but got %d", len(l2))
   694  	}
   695  
   696  	switch l2[0].(type) {
   697  	case *net.TCPListener:
   698  	// ok
   699  	default:
   700  		t.Errorf("expected type=*net.TCPListener, got %T", l2[0])
   701  	}
   702  }