github.com/saucelabs/saucectl@v0.175.1/internal/http/testcomposer_test.go (about)

     1  package http
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"reflect"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/saucelabs/saucectl/internal/framework"
    13  	"github.com/saucelabs/saucectl/internal/iam"
    14  )
    15  
    16  func TestTestComposer_GetSlackToken(t *testing.T) {
    17  	type fields struct {
    18  		HTTPClient  *http.Client
    19  		URL         string
    20  		Credentials iam.Credentials
    21  	}
    22  	tests := []struct {
    23  		name       string
    24  		fields     fields
    25  		want       string
    26  		wantErr    bool
    27  		serverFunc func(w http.ResponseWriter, r *http.Request)
    28  	}{
    29  		{
    30  			name:    "token exists",
    31  			want:    "user token",
    32  			wantErr: false,
    33  			serverFunc: func(w http.ResponseWriter, r *http.Request) {
    34  				w.WriteHeader(200)
    35  				err := json.NewEncoder(w).Encode(TokenResponse{
    36  					Token: "user token",
    37  				})
    38  				if err != nil {
    39  					t.Errorf("failed to encode json response: %v", err)
    40  				}
    41  			},
    42  		},
    43  		{
    44  			name:    "token validation error",
    45  			want:    "",
    46  			wantErr: true,
    47  			serverFunc: func(w http.ResponseWriter, r *http.Request) {
    48  				w.WriteHeader(422)
    49  			},
    50  		},
    51  		{
    52  			name:    "token does not exists",
    53  			want:    "",
    54  			wantErr: true,
    55  			serverFunc: func(w http.ResponseWriter, r *http.Request) {
    56  				w.WriteHeader(404)
    57  			},
    58  		},
    59  	}
    60  	for _, tt := range tests {
    61  		t.Run(tt.name, func(t *testing.T) {
    62  			server := httptest.NewServer(http.HandlerFunc(tt.serverFunc))
    63  			defer server.Close()
    64  
    65  			c := &TestComposer{
    66  				HTTPClient:  server.Client(),
    67  				URL:         server.URL,
    68  				Credentials: tt.fields.Credentials,
    69  			}
    70  
    71  			got, err := c.GetSlackToken(context.Background())
    72  			if (err != nil) != tt.wantErr {
    73  				t.Errorf("GetSlackToken error = %v, wantErr %v", err, tt.wantErr)
    74  				return
    75  			}
    76  			if !reflect.DeepEqual(got, tt.want) {
    77  				t.Errorf("GetSlackToken got = %v, want %v", got, tt.want)
    78  			}
    79  		})
    80  	}
    81  }
    82  
    83  func TestTestComposer_UploadAsset(t *testing.T) {
    84  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    85  		var err error
    86  		switch r.URL.Path {
    87  		case "/v1/testcomposer/jobs/1/assets":
    88  			w.WriteHeader(http.StatusOK)
    89  			_, err = w.Write([]byte("{\"uploaded\":null}"))
    90  		case "/v1/testcomposer/jobs/2/assets":
    91  			w.WriteHeader(http.StatusOK)
    92  			_, err = w.Write([]byte("{\"uploaded\":null,\"errors\":[\"failed to upload config.yml: content-type not allowed\"]}"))
    93  		case "/v1/testcomposer/jobs/3/assets":
    94  			w.WriteHeader(http.StatusNotFound)
    95  		default:
    96  			w.WriteHeader(http.StatusInternalServerError)
    97  		}
    98  
    99  		if err != nil {
   100  			t.Errorf("failed to respond: %v", err)
   101  		}
   102  	}))
   103  	defer ts.Close()
   104  	// timeout := 3 * time.Second
   105  
   106  	type args struct {
   107  		jobID       string
   108  		fileName    string
   109  		contentType string
   110  		content     []byte
   111  	}
   112  	tests := []struct {
   113  		client  TestComposer
   114  		name    string
   115  		args    args
   116  		wantErr bool
   117  	}{
   118  		{
   119  			name: "Valid case",
   120  			client: TestComposer{
   121  				HTTPClient:  ts.Client(),
   122  				URL:         ts.URL,
   123  				Credentials: iam.Credentials{Username: "test", AccessKey: "123"},
   124  			},
   125  			args: args{
   126  				jobID:       "1",
   127  				fileName:    "config.yml",
   128  				contentType: "text/plain",
   129  				content:     []byte("dummy-content"),
   130  			},
   131  			wantErr: false,
   132  		},
   133  		{
   134  			name: "invalid case - 400",
   135  			client: TestComposer{
   136  				HTTPClient:  ts.Client(),
   137  				URL:         ts.URL,
   138  				Credentials: iam.Credentials{Username: "test", AccessKey: "123"},
   139  			},
   140  			args: args{
   141  				jobID:       "2",
   142  				fileName:    "config.yml",
   143  				contentType: "text/plain",
   144  				content:     []byte("dummy-content"),
   145  			},
   146  			wantErr: true,
   147  		},
   148  		{
   149  			name: "invalid 404",
   150  			client: TestComposer{
   151  				HTTPClient:  ts.Client(),
   152  				URL:         ts.URL,
   153  				Credentials: iam.Credentials{Username: "test", AccessKey: "123"},
   154  			},
   155  			args: args{
   156  				jobID:       "3",
   157  				fileName:    "config.yml",
   158  				contentType: "text/plain",
   159  				content:     []byte("dummy-content"),
   160  			},
   161  			wantErr: true,
   162  		},
   163  	}
   164  	for _, tt := range tests {
   165  		t.Run(tt.name, func(t *testing.T) {
   166  			if err := tt.client.UploadAsset(tt.args.jobID, false, tt.args.fileName, tt.args.contentType, tt.args.content); (err != nil) != tt.wantErr {
   167  				t.Errorf("UploadAsset() error = %v, wantErr %v", err, tt.wantErr)
   168  			}
   169  		})
   170  	}
   171  }
   172  
   173  func TestTestComposer_Frameworks(t *testing.T) {
   174  	tests := []struct {
   175  		name     string
   176  		body     string
   177  		httpCode int
   178  		want     []string
   179  		wantErr  bool
   180  	}{
   181  		{
   182  			name:     "HTTP - 200",
   183  			body:     `[{"name":"cypress","version":"12.6.0"},{"name":"cypress","version":"12.3.0"},{"name":"playwright","version":"1.31.1"},{"name":"playwright","version":"1.29.2"},{"name":"puppeteer-replay","version":"0.8.0"},{"name":"puppeteer-replay","version":"0.7.0"},{"name":"testcafe","version":"2.1.0"},{"name":"testcafe","version":"2.0.1"}]`,
   184  			httpCode: 200,
   185  			want: []string{
   186  				"cypress",
   187  				"playwright",
   188  				"puppeteer-replay",
   189  				"testcafe",
   190  			},
   191  			wantErr: false,
   192  		},
   193  		{
   194  			name:     "HTTP - 500",
   195  			body:     ``,
   196  			httpCode: 500,
   197  			want:     []string{},
   198  			wantErr:  true,
   199  		},
   200  	}
   201  	for _, tt := range tests {
   202  		t.Run(tt.name, func(t *testing.T) {
   203  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   204  				var err error
   205  				switch r.URL.Path {
   206  				case "/v2/testcomposer/frameworks":
   207  					w.WriteHeader(tt.httpCode)
   208  					_, err = w.Write([]byte(tt.body))
   209  				default:
   210  					w.WriteHeader(http.StatusInternalServerError)
   211  				}
   212  				if err != nil {
   213  					t.Errorf("failed to respond: %v", err)
   214  				}
   215  			}))
   216  			c := &TestComposer{
   217  				HTTPClient:  http.DefaultClient,
   218  				URL:         ts.URL,
   219  				Credentials: iam.Credentials{Username: "test", AccessKey: "123"},
   220  			}
   221  			got, err := c.Frameworks(context.Background())
   222  			if (err != nil) != tt.wantErr {
   223  				t.Errorf("Frameworks() error = %v, wantErr %v", err, tt.wantErr)
   224  				return
   225  			}
   226  			if !reflect.DeepEqual(got, tt.want) {
   227  				t.Errorf("Frameworks() got = %v, want %v", got, tt.want)
   228  			}
   229  			ts.Close()
   230  		})
   231  	}
   232  }
   233  
   234  func TestTestComposer_Versions(t *testing.T) {
   235  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   236  		var err error
   237  		switch r.RequestURI {
   238  		case "/v2/testcomposer/frameworks?frameworkName=cypress":
   239  			w.WriteHeader(http.StatusOK)
   240  			_, err = w.Write([]byte(`[{"name":"cypress","version":"7.3.0","eolDate":"2023-01-01T00:00:00Z","removalDate":"2023-04-01T00:00:00Z","runner":{"cloudRunnerVersion":"","dockerImage":"saucelabs/stt-cypress-mocha-node:v7.1.1","gitRelease":"saucelabs/sauce-cypress-runner:v7.1.1"},"platforms":[{"name":"windows 10","browsers":["googlechrome","firefox","microsoftedge"]}]},{"name":"cypress","version":"7.1.0","eolDate":"2023-01-01T00:00:00Z","removalDate":"2023-04-01T00:00:00Z","runner":{"cloudRunnerVersion":"","dockerImage":"saucelabs/stt-cypress-mocha-node:v7.0.6","gitRelease":"saucelabs/sauce-cypress-runner:v7.0.6"},"platforms":[{"name":"windows 10","browsers":["googlechrome","firefox","microsoftedge"]}]},{"name":"cypress","version":"6.6.0","eolDate":"2023-01-01T00:00:00Z","removalDate":"2023-04-01T00:00:00Z","runner":{"cloudRunnerVersion":"","dockerImage":"saucelabs/stt-cypress-mocha-node:v6.0.2","gitRelease":"saucelabs/sauce-cypress-runner:v6.0.2"},"platforms":[{"name":"windows 10","browsers":["googlechrome","firefox","microsoftedge"]}]}]`))
   241  		case "/v2/testcomposer/frameworks?frameworkName=non-existent":
   242  			w.WriteHeader(http.StatusOK)
   243  			_, err = w.Write([]byte(`[]`))
   244  		default:
   245  			w.WriteHeader(http.StatusInternalServerError)
   246  		}
   247  
   248  		if err != nil {
   249  			t.Errorf("failed to respond: %v", err)
   250  		}
   251  	}))
   252  	defer ts.Close()
   253  	c := &TestComposer{
   254  		HTTPClient:  ts.Client(),
   255  		URL:         ts.URL,
   256  		Credentials: iam.Credentials{Username: "test", AccessKey: "123"},
   257  	}
   258  	type args struct {
   259  		frameworkName string
   260  	}
   261  	tests := []struct {
   262  		name    string
   263  		want    []framework.Metadata
   264  		args    args
   265  		wantErr bool
   266  	}{
   267  		{
   268  			name: "HTTP - 200",
   269  			args: args{
   270  				frameworkName: "cypress",
   271  			},
   272  			want: []framework.Metadata{
   273  				{
   274  					FrameworkName:    "cypress",
   275  					FrameworkVersion: "7.3.0",
   276  					EOLDate:          time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC),
   277  					RemovalDate:      time.Date(2023, 04, 01, 0, 0, 0, 0, time.UTC),
   278  					GitRelease:       "saucelabs/sauce-cypress-runner:v7.1.1",
   279  					DockerImage:      "saucelabs/stt-cypress-mocha-node:v7.1.1",
   280  					Platforms: []framework.Platform{
   281  						{
   282  							PlatformName: "windows 10",
   283  							BrowserNames: []string{"googlechrome", "firefox", "microsoftedge"},
   284  						},
   285  					},
   286  				}, {
   287  					FrameworkName:    "cypress",
   288  					FrameworkVersion: "7.1.0",
   289  					EOLDate:          time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC),
   290  					RemovalDate:      time.Date(2023, 04, 01, 0, 0, 0, 0, time.UTC),
   291  					GitRelease:       "saucelabs/sauce-cypress-runner:v7.0.6",
   292  					DockerImage:      "saucelabs/stt-cypress-mocha-node:v7.0.6",
   293  					Platforms: []framework.Platform{
   294  						{
   295  							PlatformName: "windows 10",
   296  							BrowserNames: []string{"googlechrome", "firefox", "microsoftedge"},
   297  						},
   298  					},
   299  				}, {
   300  					FrameworkName:    "cypress",
   301  					FrameworkVersion: "6.6.0",
   302  					EOLDate:          time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC),
   303  					RemovalDate:      time.Date(2023, 04, 01, 0, 0, 0, 0, time.UTC),
   304  					GitRelease:       "saucelabs/sauce-cypress-runner:v6.0.2",
   305  					DockerImage:      "saucelabs/stt-cypress-mocha-node:v6.0.2",
   306  					Platforms: []framework.Platform{
   307  						{
   308  							PlatformName: "windows 10",
   309  							BrowserNames: []string{"googlechrome", "firefox", "microsoftedge"},
   310  						},
   311  					},
   312  				},
   313  			},
   314  			wantErr: false,
   315  		}, {
   316  			name: "HTTP - 500",
   317  			args: args{
   318  				frameworkName: "buggy",
   319  			},
   320  			want:    []framework.Metadata{},
   321  			wantErr: true,
   322  		}, {
   323  			name: "HTTP - Non-existent framework",
   324  			args: args{
   325  				frameworkName: "non-existent",
   326  			},
   327  			wantErr: false,
   328  		},
   329  	}
   330  	for _, tt := range tests {
   331  		t.Run(tt.name, func(t *testing.T) {
   332  			got, err := c.Versions(context.Background(), tt.args.frameworkName)
   333  			if (err != nil) != tt.wantErr {
   334  				t.Errorf("Versions() error = %v, wantErr %v", err, tt.wantErr)
   335  				return
   336  			}
   337  			if !reflect.DeepEqual(got, tt.want) {
   338  				t.Errorf("Versions() got = %v, want %v", got, tt.want)
   339  			}
   340  		})
   341  	}
   342  }