github.com/apptainer/singularity@v3.1.1+incompatible/pkg/client/library/api_test.go (about)

     1  // Copyright (c) 2018, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package client
     7  
     8  import (
     9  	"encoding/json"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"os"
    13  	"reflect"
    14  	"testing"
    15  
    16  	"github.com/globalsign/mgo/bson"
    17  	"github.com/sylabs/singularity/internal/pkg/test"
    18  	useragent "github.com/sylabs/singularity/pkg/util/user-agent"
    19  )
    20  
    21  const testToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM"
    22  
    23  var (
    24  	testEntity = Entity{
    25  		ID:          bson.NewObjectId(),
    26  		Name:        "test-user",
    27  		Description: "A test user",
    28  	}
    29  
    30  	testCollection = Collection{
    31  		ID:          bson.NewObjectId(),
    32  		Name:        "test-collection",
    33  		Description: "A test collection",
    34  		Entity:      testEntity.ID,
    35  		EntityName:  testEntity.Name,
    36  	}
    37  
    38  	testContainer = Container{
    39  		ID:             bson.NewObjectId(),
    40  		Name:           "test-container",
    41  		Description:    "A test container",
    42  		Entity:         testEntity.ID,
    43  		EntityName:     testEntity.Name,
    44  		Collection:     testEntity.ID,
    45  		CollectionName: testCollection.Name,
    46  		ImageTags: map[string]bson.ObjectId{
    47  			"test-tag": bson.NewObjectId(),
    48  			"latest":   bson.NewObjectId()},
    49  	}
    50  
    51  	testImage = Image{
    52  		ID:             bson.NewObjectId(),
    53  		Hash:           "sha256.e50a30881ace3d5944f5661d222db7bee5296be9e4dc7c1fcb7604bcae926e88",
    54  		Entity:         testEntity.ID,
    55  		EntityName:     testEntity.Name,
    56  		Collection:     testEntity.ID,
    57  		CollectionName: testCollection.Name,
    58  		Container:      testContainer.ID,
    59  		ContainerName:  testContainer.Name,
    60  	}
    61  
    62  	testSearch = SearchResults{
    63  		Entities:    []Entity{testEntity},
    64  		Collections: []Collection{testCollection},
    65  		Containers:  []Container{testContainer},
    66  	}
    67  )
    68  
    69  type mockService struct {
    70  	t           *testing.T
    71  	code        int
    72  	body        interface{}
    73  	reqCallback func(*http.Request, *testing.T)
    74  	httpAddr    string
    75  	httpPath    string
    76  	httpServer  *httptest.Server
    77  	baseURI     string
    78  }
    79  
    80  func TestMain(m *testing.M) {
    81  	useragent.InitValue("singularity", "3.0.0-alpha.1-303-gaed8d30-dirty")
    82  
    83  	os.Exit(m.Run())
    84  }
    85  
    86  func (m *mockService) Run() {
    87  	mux := http.NewServeMux()
    88  	mux.HandleFunc(m.httpPath, m.ServeHTTP)
    89  	m.httpServer = httptest.NewServer(mux)
    90  	m.httpAddr = m.httpServer.Listener.Addr().String()
    91  	m.baseURI = "http://" + m.httpAddr
    92  }
    93  
    94  func (m *mockService) Stop() {
    95  	m.httpServer.Close()
    96  }
    97  
    98  func (m *mockService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    99  
   100  	if m.reqCallback != nil {
   101  		m.reqCallback(r, m.t)
   102  	}
   103  	w.WriteHeader(m.code)
   104  	err := json.NewEncoder(w).Encode(&m.body)
   105  	if err != nil {
   106  		m.t.Errorf("Error encoding mock response: %v", err)
   107  	}
   108  }
   109  
   110  func Test_getEntity(t *testing.T) {
   111  
   112  	tests := []struct {
   113  		description  string
   114  		code         int
   115  		body         interface{}
   116  		reqCallback  func(*http.Request, *testing.T)
   117  		entityRef    string
   118  		expectEntity Entity
   119  		expectFound  bool
   120  		expectError  bool
   121  	}{
   122  		{
   123  			description:  "NotFound",
   124  			code:         http.StatusNotFound,
   125  			body:         JSONResponse{Error: JSONError{Code: http.StatusNotFound, Status: http.StatusText(http.StatusNotFound)}},
   126  			reqCallback:  nil,
   127  			entityRef:    "notthere",
   128  			expectEntity: Entity{},
   129  			expectFound:  false,
   130  			expectError:  false,
   131  		},
   132  		{
   133  			description:  "Unauthorized",
   134  			code:         http.StatusUnauthorized,
   135  			body:         JSONResponse{Error: JSONError{Code: http.StatusUnauthorized, Status: http.StatusText(http.StatusUnauthorized)}},
   136  			reqCallback:  nil,
   137  			entityRef:    "notmine",
   138  			expectEntity: Entity{},
   139  			expectFound:  false,
   140  			expectError:  true,
   141  		},
   142  		{
   143  			description:  "ValidResponse",
   144  			code:         http.StatusOK,
   145  			body:         EntityResponse{Data: testEntity, Error: JSONError{}},
   146  			reqCallback:  nil,
   147  			entityRef:    "test-user",
   148  			expectEntity: testEntity,
   149  			expectFound:  true,
   150  			expectError:  false,
   151  		},
   152  	}
   153  
   154  	// Loop over test cases
   155  	for _, tt := range tests {
   156  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   157  
   158  			m := mockService{
   159  				t:           t,
   160  				code:        tt.code,
   161  				body:        tt.body,
   162  				reqCallback: tt.reqCallback,
   163  				httpPath:    "/v1/entities/" + tt.entityRef,
   164  			}
   165  
   166  			m.Run()
   167  
   168  			entity, found, err := getEntity(m.baseURI, testToken, tt.entityRef)
   169  
   170  			if err != nil && !tt.expectError {
   171  				t.Errorf("Unexpected error: %v", err)
   172  			}
   173  			if err == nil && tt.expectError {
   174  				t.Errorf("Unexpected success. Expected error.")
   175  			}
   176  			if found != tt.expectFound {
   177  				t.Errorf("Got found %v - expected %v", found, tt.expectFound)
   178  			}
   179  			if !reflect.DeepEqual(entity, tt.expectEntity) {
   180  				t.Errorf("Got entity %v - expected %v", entity, tt.expectEntity)
   181  			}
   182  
   183  			m.Stop()
   184  
   185  		}))
   186  
   187  	}
   188  }
   189  
   190  func Test_getCollection(t *testing.T) {
   191  
   192  	tests := []struct {
   193  		description      string
   194  		code             int
   195  		body             interface{}
   196  		reqCallback      func(*http.Request, *testing.T)
   197  		collectionRef    string
   198  		expectCollection Collection
   199  		expectFound      bool
   200  		expectError      bool
   201  	}{
   202  		{
   203  			description:      "NotFound",
   204  			code:             http.StatusNotFound,
   205  			body:             JSONResponse{Error: JSONError{Code: http.StatusNotFound, Status: http.StatusText(http.StatusNotFound)}},
   206  			reqCallback:      nil,
   207  			collectionRef:    "notthere",
   208  			expectCollection: Collection{},
   209  			expectFound:      false,
   210  			expectError:      false,
   211  		},
   212  		{
   213  			description:      "Unauthorized",
   214  			code:             http.StatusUnauthorized,
   215  			body:             JSONResponse{Error: JSONError{Code: http.StatusUnauthorized, Status: http.StatusText(http.StatusUnauthorized)}},
   216  			reqCallback:      nil,
   217  			collectionRef:    "notmine",
   218  			expectCollection: Collection{},
   219  			expectFound:      false,
   220  			expectError:      true,
   221  		},
   222  		{
   223  			description:      "ValidResponse",
   224  			code:             http.StatusOK,
   225  			body:             CollectionResponse{Data: testCollection, Error: JSONError{}},
   226  			reqCallback:      nil,
   227  			collectionRef:    "test-entity/test-collection",
   228  			expectCollection: testCollection,
   229  			expectFound:      true,
   230  			expectError:      false,
   231  		},
   232  	}
   233  
   234  	// Loop over test cases
   235  	for _, tt := range tests {
   236  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   237  
   238  			m := mockService{
   239  				t:           t,
   240  				code:        tt.code,
   241  				body:        tt.body,
   242  				reqCallback: tt.reqCallback,
   243  				httpPath:    "/v1/collections/" + tt.collectionRef,
   244  			}
   245  
   246  			m.Run()
   247  
   248  			collection, found, err := getCollection(m.baseURI, testToken, tt.collectionRef)
   249  
   250  			if err != nil && !tt.expectError {
   251  				t.Errorf("Unexpected error: %v", err)
   252  			}
   253  			if err == nil && tt.expectError {
   254  				t.Errorf("Unexpected success. Expected error.")
   255  			}
   256  			if found != tt.expectFound {
   257  				t.Errorf("Got found %v - expected %v", found, tt.expectFound)
   258  			}
   259  			if !reflect.DeepEqual(collection, tt.expectCollection) {
   260  				t.Errorf("Got entity %v - expected %v", collection, tt.expectCollection)
   261  			}
   262  
   263  			m.Stop()
   264  
   265  		}))
   266  
   267  	}
   268  }
   269  
   270  func Test_getContainer(t *testing.T) {
   271  
   272  	tests := []struct {
   273  		description     string
   274  		code            int
   275  		body            interface{}
   276  		reqCallback     func(*http.Request, *testing.T)
   277  		containerRef    string
   278  		expectContainer Container
   279  		expectFound     bool
   280  		expectError     bool
   281  	}{
   282  		{
   283  			description:     "NotFound",
   284  			code:            http.StatusNotFound,
   285  			body:            JSONResponse{Error: JSONError{Code: http.StatusNotFound, Status: http.StatusText(http.StatusNotFound)}},
   286  			reqCallback:     nil,
   287  			containerRef:    "notthere",
   288  			expectContainer: Container{},
   289  			expectFound:     false,
   290  			expectError:     false,
   291  		},
   292  		{
   293  			description:     "Unauthorized",
   294  			code:            http.StatusUnauthorized,
   295  			body:            JSONResponse{Error: JSONError{Code: http.StatusUnauthorized, Status: http.StatusText(http.StatusUnauthorized)}},
   296  			reqCallback:     nil,
   297  			containerRef:    "notmine",
   298  			expectContainer: Container{},
   299  			expectFound:     false,
   300  			expectError:     true,
   301  		},
   302  		{
   303  			description:     "ValidResponse",
   304  			code:            http.StatusOK,
   305  			body:            ContainerResponse{Data: testContainer, Error: JSONError{}},
   306  			reqCallback:     nil,
   307  			containerRef:    "test-entity/test-collection/test-container",
   308  			expectContainer: testContainer,
   309  			expectFound:     true,
   310  			expectError:     false,
   311  		},
   312  	}
   313  
   314  	// Loop over test cases
   315  	for _, tt := range tests {
   316  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   317  
   318  			m := mockService{
   319  				t:           t,
   320  				code:        tt.code,
   321  				body:        tt.body,
   322  				reqCallback: tt.reqCallback,
   323  				httpPath:    "/v1/containers/" + tt.containerRef,
   324  			}
   325  
   326  			m.Run()
   327  
   328  			container, found, err := getContainer(m.baseURI, testToken, tt.containerRef)
   329  
   330  			if err != nil && !tt.expectError {
   331  				t.Errorf("Unexpected error: %v", err)
   332  			}
   333  			if err == nil && tt.expectError {
   334  				t.Errorf("Unexpected success. Expected error.")
   335  			}
   336  			if found != tt.expectFound {
   337  				t.Errorf("Got found %v - expected %v", found, tt.expectFound)
   338  			}
   339  			if !reflect.DeepEqual(container, tt.expectContainer) {
   340  				t.Errorf("Got container %v - expected %v", container, tt.expectContainer)
   341  			}
   342  
   343  			m.Stop()
   344  
   345  		}))
   346  
   347  	}
   348  }
   349  
   350  func Test_getImage(t *testing.T) {
   351  
   352  	tests := []struct {
   353  		description string
   354  		code        int
   355  		body        interface{}
   356  		reqCallback func(*http.Request, *testing.T)
   357  		imageRef    string
   358  		expectImage Image
   359  		expectFound bool
   360  		expectError bool
   361  	}{
   362  		{
   363  			description: "NotFound",
   364  			code:        http.StatusNotFound,
   365  			body:        JSONResponse{Error: JSONError{Code: http.StatusNotFound, Status: http.StatusText(http.StatusNotFound)}},
   366  			reqCallback: nil,
   367  			imageRef:    "notthere",
   368  			expectImage: Image{},
   369  			expectFound: false,
   370  			expectError: false,
   371  		},
   372  		{
   373  			description: "Unauthorized",
   374  			code:        http.StatusUnauthorized,
   375  			body:        JSONResponse{Error: JSONError{Code: http.StatusUnauthorized, Status: http.StatusText(http.StatusUnauthorized)}},
   376  			reqCallback: nil,
   377  			imageRef:    "notmine",
   378  			expectImage: Image{},
   379  			expectFound: false,
   380  			expectError: true,
   381  		},
   382  		{
   383  			description: "ValidResponse",
   384  			code:        http.StatusOK,
   385  			body:        ImageResponse{Data: testImage, Error: JSONError{}},
   386  			reqCallback: nil,
   387  			imageRef:    "test",
   388  			expectImage: testImage,
   389  			expectFound: true,
   390  			expectError: false,
   391  		},
   392  	}
   393  
   394  	// Loop over test cases
   395  	for _, tt := range tests {
   396  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   397  
   398  			m := mockService{
   399  				t:           t,
   400  				code:        tt.code,
   401  				body:        tt.body,
   402  				reqCallback: tt.reqCallback,
   403  				httpPath:    "/v1/images/" + tt.imageRef,
   404  			}
   405  
   406  			m.Run()
   407  
   408  			image, found, err := getImage(m.baseURI, testToken, tt.imageRef)
   409  
   410  			if err != nil && !tt.expectError {
   411  				t.Errorf("Unexpected error: %v", err)
   412  			}
   413  			if err == nil && tt.expectError {
   414  				t.Errorf("Unexpected success. Expected error.")
   415  			}
   416  			if found != tt.expectFound {
   417  				t.Errorf("Got found %v - expected %v", found, tt.expectFound)
   418  			}
   419  			if !reflect.DeepEqual(image, tt.expectImage) {
   420  				t.Errorf("Got image %v - expected %v", image, tt.expectImage)
   421  			}
   422  
   423  			m.Stop()
   424  
   425  		}))
   426  
   427  	}
   428  }
   429  
   430  func Test_createEntity(t *testing.T) {
   431  
   432  	tests := []struct {
   433  		description  string
   434  		code         int
   435  		body         interface{}
   436  		reqCallback  func(*http.Request, *testing.T)
   437  		entityRef    string
   438  		expectEntity Entity
   439  		expectError  bool
   440  	}{
   441  		{
   442  			description:  "Valid Request",
   443  			code:         http.StatusOK,
   444  			body:         EntityResponse{Data: testEntity, Error: JSONError{}},
   445  			entityRef:    "test",
   446  			expectEntity: testEntity,
   447  			expectError:  false,
   448  		},
   449  		{
   450  			description:  "Error response",
   451  			code:         http.StatusInternalServerError,
   452  			body:         Entity{},
   453  			entityRef:    "test",
   454  			expectEntity: Entity{},
   455  			expectError:  true,
   456  		},
   457  	}
   458  
   459  	// Loop over test cases
   460  	for _, tt := range tests {
   461  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   462  
   463  			m := mockService{
   464  				t:           t,
   465  				code:        tt.code,
   466  				body:        tt.body,
   467  				reqCallback: tt.reqCallback,
   468  				httpPath:    "/v1/entities/",
   469  			}
   470  
   471  			m.Run()
   472  
   473  			entity, err := createEntity(m.baseURI, testToken, tt.entityRef)
   474  
   475  			if err != nil && !tt.expectError {
   476  				t.Errorf("Unexpected error: %v", err)
   477  			}
   478  			if err == nil && tt.expectError {
   479  				t.Errorf("Unexpected success. Expected error.")
   480  			}
   481  			if !reflect.DeepEqual(entity, tt.expectEntity) {
   482  				t.Errorf("Got created entity %v - expected %v", entity, tt.expectEntity)
   483  			}
   484  
   485  			m.Stop()
   486  
   487  		}))
   488  
   489  	}
   490  }
   491  
   492  func Test_createCollection(t *testing.T) {
   493  
   494  	tests := []struct {
   495  		description      string
   496  		code             int
   497  		body             interface{}
   498  		reqCallback      func(*http.Request, *testing.T)
   499  		collectionRef    string
   500  		expectCollection Collection
   501  		expectError      bool
   502  	}{
   503  		{
   504  			description:      "Valid Request",
   505  			code:             http.StatusOK,
   506  			body:             CollectionResponse{Data: Collection{Name: "test"}, Error: JSONError{}},
   507  			collectionRef:    "test",
   508  			expectCollection: Collection{Name: "test"},
   509  			expectError:      false,
   510  		},
   511  		{
   512  			description:      "Error response",
   513  			code:             http.StatusInternalServerError,
   514  			body:             Collection{},
   515  			collectionRef:    "test",
   516  			expectCollection: Collection{},
   517  			expectError:      true,
   518  		},
   519  	}
   520  
   521  	// Loop over test cases
   522  	for _, tt := range tests {
   523  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   524  
   525  			m := mockService{
   526  				t:           t,
   527  				code:        tt.code,
   528  				body:        tt.body,
   529  				reqCallback: tt.reqCallback,
   530  				httpPath:    "/v1/collections/",
   531  			}
   532  
   533  			m.Run()
   534  
   535  			collection, err := createCollection(m.baseURI, testToken, tt.collectionRef, bson.NewObjectId().Hex())
   536  
   537  			if err != nil && !tt.expectError {
   538  				t.Errorf("Unexpected error: %v", err)
   539  			}
   540  			if err == nil && tt.expectError {
   541  				t.Errorf("Unexpected success. Expected error.")
   542  			}
   543  			if !reflect.DeepEqual(collection, tt.expectCollection) {
   544  				t.Errorf("Got created collection %v - expected %v", collection, tt.expectCollection)
   545  			}
   546  
   547  			m.Stop()
   548  
   549  		}))
   550  
   551  	}
   552  }
   553  
   554  func Test_createContainer(t *testing.T) {
   555  
   556  	tests := []struct {
   557  		description     string
   558  		code            int
   559  		body            interface{}
   560  		reqCallback     func(*http.Request, *testing.T)
   561  		containerRef    string
   562  		expectContainer Container
   563  		expectError     bool
   564  	}{
   565  		{
   566  			description:     "Valid Request",
   567  			code:            http.StatusOK,
   568  			body:            ContainerResponse{Data: Container{Name: "test"}, Error: JSONError{}},
   569  			containerRef:    "test",
   570  			expectContainer: Container{Name: "test"},
   571  			expectError:     false,
   572  		},
   573  		{
   574  			description:     "Error response",
   575  			code:            http.StatusInternalServerError,
   576  			body:            Container{},
   577  			containerRef:    "test",
   578  			expectContainer: Container{},
   579  			expectError:     true,
   580  		},
   581  	}
   582  
   583  	// Loop over test cases
   584  	for _, tt := range tests {
   585  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   586  
   587  			m := mockService{
   588  				t:           t,
   589  				code:        tt.code,
   590  				body:        tt.body,
   591  				reqCallback: tt.reqCallback,
   592  				httpPath:    "/v1/containers/",
   593  			}
   594  
   595  			m.Run()
   596  
   597  			container, err := createContainer(m.baseURI, testToken, tt.containerRef, bson.NewObjectId().Hex())
   598  
   599  			if err != nil && !tt.expectError {
   600  				t.Errorf("Unexpected error: %v", err)
   601  			}
   602  			if err == nil && tt.expectError {
   603  				t.Errorf("Unexpected success. Expected error.")
   604  			}
   605  			if !reflect.DeepEqual(container, tt.expectContainer) {
   606  				t.Errorf("Got created collection %v - expected %v", container, tt.expectContainer)
   607  			}
   608  
   609  			m.Stop()
   610  
   611  		}))
   612  
   613  	}
   614  }
   615  
   616  func Test_createImage(t *testing.T) {
   617  
   618  	tests := []struct {
   619  		description string
   620  		code        int
   621  		body        interface{}
   622  		reqCallback func(*http.Request, *testing.T)
   623  		imageRef    string
   624  		expectImage Image
   625  		expectError bool
   626  	}{
   627  		{
   628  			description: "Valid Request",
   629  			code:        http.StatusOK,
   630  			body:        ImageResponse{Data: Image{Hash: "sha256.e50a30881ace3d5944f5661d222db7bee5296be9e4dc7c1fcb7604bcae926e88"}, Error: JSONError{}},
   631  			imageRef:    "test",
   632  			expectImage: Image{Hash: "sha256.e50a30881ace3d5944f5661d222db7bee5296be9e4dc7c1fcb7604bcae926e88"},
   633  			expectError: false,
   634  		},
   635  		{
   636  			description: "Error response",
   637  			code:        http.StatusInternalServerError,
   638  			body:        Image{},
   639  			imageRef:    "test",
   640  			expectImage: Image{},
   641  			expectError: true,
   642  		},
   643  	}
   644  
   645  	// Loop over test cases
   646  	for _, tt := range tests {
   647  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   648  
   649  			m := mockService{
   650  				t:           t,
   651  				code:        tt.code,
   652  				body:        tt.body,
   653  				reqCallback: tt.reqCallback,
   654  				httpPath:    "/v1/images/",
   655  			}
   656  
   657  			m.Run()
   658  
   659  			image, err := createImage(m.baseURI, testToken, tt.imageRef, bson.NewObjectId().Hex(), "No Description")
   660  
   661  			if err != nil && !tt.expectError {
   662  				t.Errorf("Unexpected error: %v", err)
   663  			}
   664  			if err == nil && tt.expectError {
   665  				t.Errorf("Unexpected success. Expected error.")
   666  			}
   667  			if !reflect.DeepEqual(image, tt.expectImage) {
   668  				t.Errorf("Got created collection %v - expected %v", image, tt.expectImage)
   669  			}
   670  
   671  			m.Stop()
   672  
   673  		}))
   674  
   675  	}
   676  }
   677  
   678  func Test_setTags(t *testing.T) {
   679  
   680  	tests := []struct {
   681  		description  string
   682  		code         int
   683  		reqCallback  func(*http.Request, *testing.T)
   684  		containerRef string
   685  		imageRef     string
   686  		tags         []string
   687  		expectError  bool
   688  	}{
   689  		{
   690  			description:  "Valid Request",
   691  			code:         http.StatusOK,
   692  			containerRef: "test",
   693  			imageRef:     bson.NewObjectId().Hex(),
   694  			tags:         []string{"tag1", "tag2", "tag3"},
   695  			expectError:  false,
   696  		},
   697  		{
   698  			description:  "Error response",
   699  			code:         http.StatusInternalServerError,
   700  			containerRef: "test",
   701  			imageRef:     bson.NewObjectId().Hex(),
   702  			tags:         []string{"tag1", "tag2", "tag3"},
   703  			expectError:  true,
   704  		},
   705  	}
   706  
   707  	// Loop over test cases
   708  	for _, tt := range tests {
   709  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   710  
   711  			m := mockService{
   712  				t:           t,
   713  				code:        tt.code,
   714  				reqCallback: tt.reqCallback,
   715  				httpPath:    "/v1/tags/" + tt.containerRef,
   716  			}
   717  
   718  			m.Run()
   719  
   720  			err := setTags(m.baseURI, testToken, tt.containerRef, tt.imageRef, tt.tags)
   721  
   722  			if err != nil && !tt.expectError {
   723  				t.Errorf("Unexpected error: %v", err)
   724  			}
   725  			if err == nil && tt.expectError {
   726  				t.Errorf("Unexpected success. Expected error.")
   727  			}
   728  
   729  			m.Stop()
   730  
   731  		}))
   732  
   733  	}
   734  }
   735  
   736  func Test_search(t *testing.T) {
   737  	tests := []struct {
   738  		description   string
   739  		code          int
   740  		body          interface{}
   741  		reqCallback   func(*http.Request, *testing.T)
   742  		value         string
   743  		expectResults SearchResults
   744  		expectError   bool
   745  	}{
   746  		{
   747  			description:   "ValidRequest",
   748  			value:         "test",
   749  			code:          http.StatusOK,
   750  			body:          JSONResponse{Data: testSearch, Error: JSONError{}},
   751  			expectResults: testSearch,
   752  			expectError:   false,
   753  		},
   754  		{
   755  			description: "InternalServerError",
   756  			value:       "test",
   757  			code:        http.StatusInternalServerError,
   758  			expectError: true,
   759  		},
   760  		{
   761  			description: "BadRequest",
   762  			value:       "test",
   763  			code:        http.StatusBadRequest,
   764  			expectError: true,
   765  		},
   766  	}
   767  
   768  	// Loop over test cases
   769  	for _, tt := range tests {
   770  		t.Run(tt.description, test.WithoutPrivilege(func(t *testing.T) {
   771  
   772  			m := mockService{
   773  				t:           t,
   774  				code:        tt.code,
   775  				body:        tt.body,
   776  				reqCallback: tt.reqCallback,
   777  				httpPath:    "/v1/search",
   778  			}
   779  
   780  			m.Run()
   781  
   782  			results, err := search(m.baseURI, testToken, tt.value)
   783  
   784  			if err != nil && !tt.expectError {
   785  				t.Errorf("Unexpected error: %v", err)
   786  			}
   787  			if err == nil && tt.expectError {
   788  				t.Errorf("Unexpected success. Expected error.")
   789  			}
   790  			if !reflect.DeepEqual(results, tt.expectResults) {
   791  				t.Errorf("Got created collection %v - expected %v", results, tt.expectResults)
   792  			}
   793  
   794  			m.Stop()
   795  
   796  		}))
   797  
   798  	}
   799  }