github.com/pelicanplatform/pelican@v1.0.5/namespace_registry/registry_ui_test.go (about)

     1  package nsregistry
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"testing"
    12  
    13  	"github.com/gin-gonic/gin"
    14  	"github.com/lestrrat-go/jwx/v2/jwa"
    15  	"github.com/lestrrat-go/jwx/v2/jwk"
    16  	"github.com/pkg/errors"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  func GenerateMockJWKS() (string, error) {
    22  	// Create a private key to use for the test
    23  	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    24  	if err != nil {
    25  		return "", errors.Wrap(err, "Error generating private key")
    26  	}
    27  
    28  	// Convert from raw ecdsa to jwk.Key
    29  	pKey, err := jwk.FromRaw(privateKey)
    30  	if err != nil {
    31  		return "", errors.Wrap(err, "Unable to convert ecdsa.PrivateKey to jwk.Key")
    32  	}
    33  
    34  	//Assign Key id to the private key
    35  	err = jwk.AssignKeyID(pKey)
    36  	if err != nil {
    37  		return "", errors.Wrap(err, "Error assigning kid to private key")
    38  	}
    39  
    40  	//Set an algorithm for the key
    41  	err = pKey.Set(jwk.AlgorithmKey, jwa.ES256)
    42  	if err != nil {
    43  		return "", errors.Wrap(err, "Unable to set algorithm for pKey")
    44  	}
    45  
    46  	publicKey, err := pKey.PublicKey()
    47  	if err != nil {
    48  		return "", errors.Wrap(err, "Unable to get the public key from private key")
    49  	}
    50  
    51  	jwks := jwk.NewSet()
    52  	err = jwks.AddKey(publicKey)
    53  	if err != nil {
    54  		return "", errors.Wrap(err, "Unable to add public key to the jwks")
    55  	}
    56  
    57  	jsonData, err := json.MarshalIndent(jwks, "", "  ")
    58  	if err != nil {
    59  		return "", errors.Wrap(err, "Unable to marshall the json into string")
    60  	}
    61  	// Append a new line to the JSON data
    62  	jsonData = append(jsonData, '\n')
    63  
    64  	return string(jsonData), nil
    65  }
    66  
    67  func TestListNamespaces(t *testing.T) {
    68  	// Initialize the mock database
    69  	err := setupMockNamespaceDB()
    70  	if err != nil {
    71  		t.Fatalf("Failed to set up mock namespace DB: %v", err)
    72  	}
    73  	defer teardownMockNamespaceDB()
    74  
    75  	router := gin.Default()
    76  
    77  	router.GET("/namespaces", listNamespaces)
    78  
    79  	tests := []struct {
    80  		description  string
    81  		serverType   string
    82  		expectedCode int
    83  		emptyDB      bool
    84  		expectedData []Namespace
    85  	}{
    86  		{
    87  			description:  "valid-request-with-empty-db",
    88  			serverType:   string(OriginType),
    89  			expectedCode: http.StatusOK,
    90  			emptyDB:      true,
    91  			expectedData: []Namespace{},
    92  		},
    93  		{
    94  			description:  "valid-request-with-origin-type",
    95  			serverType:   string(OriginType),
    96  			expectedCode: http.StatusOK,
    97  			expectedData: mockNssWithOrigins,
    98  		},
    99  		{
   100  			description:  "valid-request-with-cache-type",
   101  			serverType:   string(CacheType),
   102  			expectedCode: http.StatusOK,
   103  			expectedData: mockNssWithCaches,
   104  		},
   105  		{
   106  			description:  "valid-request-without-type",
   107  			serverType:   "",
   108  			expectedCode: http.StatusOK,
   109  			expectedData: mockNssWithMixed,
   110  		},
   111  		{
   112  			description:  "invalid-request-parameters",
   113  			serverType:   "random_type", // some invalid query string
   114  			expectedCode: http.StatusBadRequest,
   115  			expectedData: nil,
   116  		},
   117  	}
   118  
   119  	for _, tc := range tests {
   120  		t.Run(tc.description, func(t *testing.T) {
   121  			if !tc.emptyDB {
   122  				err := insertMockDBData(mockNssWithMixed)
   123  				if err != nil {
   124  					t.Fatalf("Failed to set up mock data: %v", err)
   125  				}
   126  			}
   127  			defer func() {
   128  				err := resetNamespaceDB()
   129  				if err != nil {
   130  					t.Fatalf("Failed to reset mock namespace DB: %v", err)
   131  				}
   132  			}()
   133  
   134  			// Create a request to the endpoint
   135  			w := httptest.NewRecorder()
   136  			requestURL := ""
   137  			if tc.serverType != "" {
   138  				requestURL = "/namespaces?server_type=" + tc.serverType
   139  			} else {
   140  				requestURL = "/namespaces"
   141  			}
   142  			req, _ := http.NewRequest("GET", requestURL, nil)
   143  			router.ServeHTTP(w, req)
   144  
   145  			// Check the response
   146  			assert.Equal(t, tc.expectedCode, w.Code)
   147  
   148  			if tc.expectedCode == http.StatusOK {
   149  				var got []Namespace
   150  				err := json.Unmarshal(w.Body.Bytes(), &got)
   151  				if err != nil {
   152  					t.Fatalf("Failed to unmarshal response body: %v", err)
   153  				}
   154  				assert.True(t, compareNamespaces(tc.expectedData, got, true), "Response data does not match expected")
   155  			}
   156  		})
   157  	}
   158  }
   159  
   160  func TestGetNamespaceJWKS(t *testing.T) {
   161  	mockPublicKey, err := GenerateMockJWKS()
   162  	if err != nil {
   163  		t.Fatalf("Failed to set up mock public key: %v", err)
   164  	}
   165  	// Initialize the mock database
   166  	err = setupMockNamespaceDB()
   167  	if err != nil {
   168  		t.Fatalf("Failed to set up mock namespace DB: %v", err)
   169  	}
   170  	defer teardownMockNamespaceDB()
   171  
   172  	router := gin.Default()
   173  
   174  	router.GET("/test/:id/pubkey", getNamespaceJWKS)
   175  
   176  	tests := []struct {
   177  		description  string
   178  		requestId    string
   179  		expectedCode int
   180  		emptyDB      bool
   181  		expectedData string
   182  	}{
   183  		{
   184  			description:  "valid-request-with-empty-key",
   185  			requestId:    "1",
   186  			expectedCode: http.StatusOK,
   187  			expectedData: mockPublicKey,
   188  		},
   189  		{
   190  			description:  "invalid-request-with-str-id",
   191  			requestId:    "crazy-id",
   192  			expectedCode: http.StatusBadRequest,
   193  			expectedData: "",
   194  		},
   195  		{
   196  			description:  "invalid-request-with-0-id",
   197  			requestId:    "0",
   198  			expectedCode: http.StatusBadRequest,
   199  		},
   200  		{
   201  			description:  "invalid-request-with-neg-id",
   202  			requestId:    "-10000",
   203  			expectedCode: http.StatusBadRequest,
   204  		},
   205  		{
   206  			description:  "invalid-request-with-empty-id",
   207  			requestId:    "",
   208  			expectedCode: http.StatusBadRequest,
   209  		},
   210  		{
   211  			description:  "invalid-request-with-id-not-found",
   212  			requestId:    "100",
   213  			expectedCode: http.StatusNotFound,
   214  		},
   215  	}
   216  
   217  	for _, tc := range tests {
   218  		t.Run(tc.description, func(t *testing.T) {
   219  			if !tc.emptyDB {
   220  				err := insertMockDBData([]Namespace{
   221  					{
   222  						ID:     1,
   223  						Prefix: "/origin1",
   224  						Pubkey: mockPublicKey,
   225  					},
   226  				})
   227  				if err != nil {
   228  					t.Fatalf("Failed to set up mock data: %v", err)
   229  				}
   230  
   231  			}
   232  			defer func() {
   233  				err := resetNamespaceDB()
   234  				if err != nil {
   235  					t.Fatalf("Failed to reset mock namespace DB: %v", err)
   236  				}
   237  			}()
   238  
   239  			// Create a request to the endpoint
   240  			w := httptest.NewRecorder()
   241  			requestURL := fmt.Sprint("/test/", tc.requestId, "/pubkey")
   242  			req, _ := http.NewRequest("GET", requestURL, nil)
   243  			router.ServeHTTP(w, req)
   244  
   245  			// Check the response
   246  			require.Equal(t, tc.expectedCode, w.Code)
   247  
   248  			if tc.expectedCode == http.StatusOK {
   249  				assert.Equal(t, tc.expectedData, w.Body.String())
   250  			}
   251  		})
   252  	}
   253  }