github.com/google/go-github/v69@v69.2.0/github/actions_artifacts_test.go (about)

     1  // Copyright 2020 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"errors"
    11  	"fmt"
    12  	"net/http"
    13  	"net/url"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/google/go-cmp/cmp"
    18  )
    19  
    20  func TestActionsService_ListArtifacts(t *testing.T) {
    21  	t.Parallel()
    22  	client, mux, _ := setup(t)
    23  
    24  	mux.HandleFunc("/repos/o/r/actions/artifacts", func(w http.ResponseWriter, r *http.Request) {
    25  		testMethod(t, r, "GET")
    26  		testFormValues(t, r, values{"page": "2", "name": "TheArtifact"})
    27  		fmt.Fprint(w,
    28  			`{
    29  				"total_count":1,
    30  				"artifacts":[{"id":1}]
    31  			}`,
    32  		)
    33  	})
    34  
    35  	opts := &ListArtifactsOptions{
    36  		Name:        Ptr("TheArtifact"),
    37  		ListOptions: ListOptions{Page: 2},
    38  	}
    39  	ctx := context.Background()
    40  	artifacts, _, err := client.Actions.ListArtifacts(ctx, "o", "r", opts)
    41  	if err != nil {
    42  		t.Errorf("Actions.ListArtifacts returned error: %v", err)
    43  	}
    44  
    45  	want := &ArtifactList{TotalCount: Ptr(int64(1)), Artifacts: []*Artifact{{ID: Ptr(int64(1))}}}
    46  	if !cmp.Equal(artifacts, want) {
    47  		t.Errorf("Actions.ListArtifacts returned %+v, want %+v", artifacts, want)
    48  	}
    49  
    50  	const methodName = "ListArtifacts"
    51  	testBadOptions(t, methodName, func() (err error) {
    52  		_, _, err = client.Actions.ListArtifacts(ctx, "\n", "\n", opts)
    53  		return err
    54  	})
    55  
    56  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    57  		got, resp, err := client.Actions.ListArtifacts(ctx, "o", "r", opts)
    58  		if got != nil {
    59  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    60  		}
    61  		return resp, err
    62  	})
    63  }
    64  
    65  func TestActionsService_ListArtifacts_invalidOwner(t *testing.T) {
    66  	t.Parallel()
    67  	client, _, _ := setup(t)
    68  
    69  	ctx := context.Background()
    70  	_, _, err := client.Actions.ListArtifacts(ctx, "%", "r", nil)
    71  	testURLParseError(t, err)
    72  }
    73  
    74  func TestActionsService_ListArtifacts_invalidRepo(t *testing.T) {
    75  	t.Parallel()
    76  	client, _, _ := setup(t)
    77  
    78  	ctx := context.Background()
    79  	_, _, err := client.Actions.ListArtifacts(ctx, "o", "%", nil)
    80  	testURLParseError(t, err)
    81  }
    82  
    83  func TestActionsService_ListArtifacts_notFound(t *testing.T) {
    84  	t.Parallel()
    85  	client, mux, _ := setup(t)
    86  
    87  	mux.HandleFunc("/repos/o/r/actions/artifacts", func(w http.ResponseWriter, r *http.Request) {
    88  		testMethod(t, r, "GET")
    89  		w.WriteHeader(http.StatusNotFound)
    90  	})
    91  
    92  	ctx := context.Background()
    93  	artifacts, resp, err := client.Actions.ListArtifacts(ctx, "o", "r", nil)
    94  	if err == nil {
    95  		t.Errorf("Expected HTTP 404 response")
    96  	}
    97  	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
    98  		t.Errorf("Actions.ListArtifacts return status %d, want %d", got, want)
    99  	}
   100  	if artifacts != nil {
   101  		t.Errorf("Actions.ListArtifacts return %+v, want nil", artifacts)
   102  	}
   103  }
   104  
   105  func TestActionsService_ListWorkflowRunArtifacts(t *testing.T) {
   106  	t.Parallel()
   107  	client, mux, _ := setup(t)
   108  
   109  	mux.HandleFunc("/repos/o/r/actions/runs/1/artifacts", func(w http.ResponseWriter, r *http.Request) {
   110  		testMethod(t, r, "GET")
   111  		testFormValues(t, r, values{"page": "2"})
   112  		fmt.Fprint(w,
   113  			`{
   114  				"total_count":1,
   115  				"artifacts":[{"id":1}]
   116  			}`,
   117  		)
   118  	})
   119  
   120  	opts := &ListOptions{Page: 2}
   121  	ctx := context.Background()
   122  	artifacts, _, err := client.Actions.ListWorkflowRunArtifacts(ctx, "o", "r", 1, opts)
   123  	if err != nil {
   124  		t.Errorf("Actions.ListWorkflowRunArtifacts returned error: %v", err)
   125  	}
   126  
   127  	want := &ArtifactList{TotalCount: Ptr(int64(1)), Artifacts: []*Artifact{{ID: Ptr(int64(1))}}}
   128  	if !cmp.Equal(artifacts, want) {
   129  		t.Errorf("Actions.ListWorkflowRunArtifacts returned %+v, want %+v", artifacts, want)
   130  	}
   131  
   132  	const methodName = "ListWorkflowRunArtifacts"
   133  	testBadOptions(t, methodName, func() (err error) {
   134  		_, _, err = client.Actions.ListWorkflowRunArtifacts(ctx, "\n", "\n", -1, opts)
   135  		return err
   136  	})
   137  
   138  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   139  		got, resp, err := client.Actions.ListWorkflowRunArtifacts(ctx, "o", "r", 1, opts)
   140  		if got != nil {
   141  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   142  		}
   143  		return resp, err
   144  	})
   145  }
   146  
   147  func TestActionsService_ListWorkflowRunArtifacts_invalidOwner(t *testing.T) {
   148  	t.Parallel()
   149  	client, _, _ := setup(t)
   150  
   151  	ctx := context.Background()
   152  	_, _, err := client.Actions.ListWorkflowRunArtifacts(ctx, "%", "r", 1, nil)
   153  	testURLParseError(t, err)
   154  }
   155  
   156  func TestActionsService_ListWorkflowRunArtifacts_invalidRepo(t *testing.T) {
   157  	t.Parallel()
   158  	client, _, _ := setup(t)
   159  
   160  	ctx := context.Background()
   161  	_, _, err := client.Actions.ListWorkflowRunArtifacts(ctx, "o", "%", 1, nil)
   162  	testURLParseError(t, err)
   163  }
   164  
   165  func TestActionsService_ListWorkflowRunArtifacts_notFound(t *testing.T) {
   166  	t.Parallel()
   167  	client, mux, _ := setup(t)
   168  
   169  	mux.HandleFunc("/repos/o/r/actions/runs/1/artifacts", func(w http.ResponseWriter, r *http.Request) {
   170  		testMethod(t, r, "GET")
   171  		w.WriteHeader(http.StatusNotFound)
   172  	})
   173  
   174  	ctx := context.Background()
   175  	artifacts, resp, err := client.Actions.ListWorkflowRunArtifacts(ctx, "o", "r", 1, nil)
   176  	if err == nil {
   177  		t.Errorf("Expected HTTP 404 response")
   178  	}
   179  	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
   180  		t.Errorf("Actions.ListWorkflowRunArtifacts return status %d, want %d", got, want)
   181  	}
   182  	if artifacts != nil {
   183  		t.Errorf("Actions.ListWorkflowRunArtifacts return %+v, want nil", artifacts)
   184  	}
   185  }
   186  
   187  func TestActionsService_GetArtifact(t *testing.T) {
   188  	t.Parallel()
   189  	client, mux, _ := setup(t)
   190  
   191  	mux.HandleFunc("/repos/o/r/actions/artifacts/1", func(w http.ResponseWriter, r *http.Request) {
   192  		testMethod(t, r, "GET")
   193  		fmt.Fprint(w, `{
   194  			"id":1,
   195  			"node_id":"xyz",
   196  			"name":"a",
   197  			"size_in_bytes":5,
   198  			"archive_download_url":"u"
   199  		}`)
   200  	})
   201  
   202  	ctx := context.Background()
   203  	artifact, _, err := client.Actions.GetArtifact(ctx, "o", "r", 1)
   204  	if err != nil {
   205  		t.Errorf("Actions.GetArtifact returned error: %v", err)
   206  	}
   207  
   208  	want := &Artifact{
   209  		ID:                 Ptr(int64(1)),
   210  		NodeID:             Ptr("xyz"),
   211  		Name:               Ptr("a"),
   212  		SizeInBytes:        Ptr(int64(5)),
   213  		ArchiveDownloadURL: Ptr("u"),
   214  	}
   215  	if !cmp.Equal(artifact, want) {
   216  		t.Errorf("Actions.GetArtifact returned %+v, want %+v", artifact, want)
   217  	}
   218  
   219  	const methodName = "GetArtifact"
   220  	testBadOptions(t, methodName, func() (err error) {
   221  		_, _, err = client.Actions.GetArtifact(ctx, "\n", "\n", -1)
   222  		return err
   223  	})
   224  
   225  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   226  		got, resp, err := client.Actions.GetArtifact(ctx, "o", "r", 1)
   227  		if got != nil {
   228  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   229  		}
   230  		return resp, err
   231  	})
   232  }
   233  
   234  func TestActionsService_GetArtifact_invalidOwner(t *testing.T) {
   235  	t.Parallel()
   236  	client, _, _ := setup(t)
   237  
   238  	ctx := context.Background()
   239  	_, _, err := client.Actions.GetArtifact(ctx, "%", "r", 1)
   240  	testURLParseError(t, err)
   241  }
   242  
   243  func TestActionsService_GetArtifact_invalidRepo(t *testing.T) {
   244  	t.Parallel()
   245  	client, _, _ := setup(t)
   246  
   247  	ctx := context.Background()
   248  	_, _, err := client.Actions.GetArtifact(ctx, "o", "%", 1)
   249  	testURLParseError(t, err)
   250  }
   251  
   252  func TestActionsService_GetArtifact_notFound(t *testing.T) {
   253  	t.Parallel()
   254  	client, mux, _ := setup(t)
   255  
   256  	mux.HandleFunc("/repos/o/r/actions/artifacts/1", func(w http.ResponseWriter, r *http.Request) {
   257  		testMethod(t, r, "GET")
   258  		w.WriteHeader(http.StatusNotFound)
   259  	})
   260  
   261  	ctx := context.Background()
   262  	artifact, resp, err := client.Actions.GetArtifact(ctx, "o", "r", 1)
   263  	if err == nil {
   264  		t.Errorf("Expected HTTP 404 response")
   265  	}
   266  	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
   267  		t.Errorf("Actions.GetArtifact return status %d, want %d", got, want)
   268  	}
   269  	if artifact != nil {
   270  		t.Errorf("Actions.GetArtifact return %+v, want nil", artifact)
   271  	}
   272  }
   273  
   274  func TestActionsService_DownloadArtifact(t *testing.T) {
   275  	t.Parallel()
   276  
   277  	tcs := []struct {
   278  		name              string
   279  		respectRateLimits bool
   280  	}{
   281  		{
   282  			name:              "withoutRateLimits",
   283  			respectRateLimits: false,
   284  		},
   285  		{
   286  			name:              "withRateLimits",
   287  			respectRateLimits: true,
   288  		},
   289  	}
   290  
   291  	for _, tc := range tcs {
   292  		tc := tc
   293  		t.Run(tc.name, func(t *testing.T) {
   294  			t.Parallel()
   295  			client, mux, _ := setup(t)
   296  			client.RateLimitRedirectionalEndpoints = tc.respectRateLimits
   297  
   298  			mux.HandleFunc("/repos/o/r/actions/artifacts/1/zip", func(w http.ResponseWriter, r *http.Request) {
   299  				testMethod(t, r, "GET")
   300  				http.Redirect(w, r, "https://github.com/artifact", http.StatusFound)
   301  			})
   302  
   303  			ctx := context.Background()
   304  			url, resp, err := client.Actions.DownloadArtifact(ctx, "o", "r", 1, 1)
   305  			if err != nil {
   306  				t.Errorf("Actions.DownloadArtifact returned error: %v", err)
   307  			}
   308  			if resp.StatusCode != http.StatusFound {
   309  				t.Errorf("Actions.DownloadArtifact returned status: %d, want %d", resp.StatusCode, http.StatusFound)
   310  			}
   311  
   312  			want := "https://github.com/artifact"
   313  			if url.String() != want {
   314  				t.Errorf("Actions.DownloadArtifact returned %+v, want %+v", url.String(), want)
   315  			}
   316  
   317  			const methodName = "DownloadArtifact"
   318  			testBadOptions(t, methodName, func() (err error) {
   319  				_, _, err = client.Actions.DownloadArtifact(ctx, "\n", "\n", -1, 1)
   320  				return err
   321  			})
   322  
   323  			// Add custom round tripper
   324  			client.client.Transport = roundTripperFunc(func(r *http.Request) (*http.Response, error) {
   325  				return nil, errors.New("failed to download artifact")
   326  			})
   327  			// propagate custom round tripper to client without CheckRedirect
   328  			client.initialize()
   329  			testBadOptions(t, methodName, func() (err error) {
   330  				_, _, err = client.Actions.DownloadArtifact(ctx, "o", "r", 1, 1)
   331  				return err
   332  			})
   333  		})
   334  	}
   335  }
   336  
   337  func TestActionsService_DownloadArtifact_invalidOwner(t *testing.T) {
   338  	t.Parallel()
   339  	tcs := []struct {
   340  		name              string
   341  		respectRateLimits bool
   342  	}{
   343  		{
   344  			name:              "withoutRateLimits",
   345  			respectRateLimits: false,
   346  		},
   347  		{
   348  			name:              "withRateLimits",
   349  			respectRateLimits: true,
   350  		},
   351  	}
   352  
   353  	for _, tc := range tcs {
   354  		tc := tc
   355  		t.Run(tc.name, func(t *testing.T) {
   356  			t.Parallel()
   357  			client, _, _ := setup(t)
   358  			client.RateLimitRedirectionalEndpoints = tc.respectRateLimits
   359  
   360  			ctx := context.Background()
   361  			_, _, err := client.Actions.DownloadArtifact(ctx, "%", "r", 1, 1)
   362  			testURLParseError(t, err)
   363  		})
   364  	}
   365  }
   366  
   367  func TestActionsService_DownloadArtifact_invalidRepo(t *testing.T) {
   368  	t.Parallel()
   369  	tcs := []struct {
   370  		name              string
   371  		respectRateLimits bool
   372  	}{
   373  		{
   374  			name:              "withoutRateLimits",
   375  			respectRateLimits: false,
   376  		},
   377  		{
   378  			name:              "withRateLimits",
   379  			respectRateLimits: true,
   380  		},
   381  	}
   382  
   383  	for _, tc := range tcs {
   384  		tc := tc
   385  		t.Run(tc.name, func(t *testing.T) {
   386  			t.Parallel()
   387  			client, _, _ := setup(t)
   388  			client.RateLimitRedirectionalEndpoints = tc.respectRateLimits
   389  
   390  			ctx := context.Background()
   391  			_, _, err := client.Actions.DownloadArtifact(ctx, "o", "%", 1, 1)
   392  			testURLParseError(t, err)
   393  		})
   394  	}
   395  }
   396  
   397  func TestActionsService_DownloadArtifact_StatusMovedPermanently_dontFollowRedirects(t *testing.T) {
   398  	t.Parallel()
   399  	tcs := []struct {
   400  		name              string
   401  		respectRateLimits bool
   402  	}{
   403  		{
   404  			name:              "withoutRateLimits",
   405  			respectRateLimits: false,
   406  		},
   407  		{
   408  			name:              "withRateLimits",
   409  			respectRateLimits: true,
   410  		},
   411  	}
   412  
   413  	for _, tc := range tcs {
   414  		tc := tc
   415  		t.Run(tc.name, func(t *testing.T) {
   416  			t.Parallel()
   417  			client, mux, _ := setup(t)
   418  			client.RateLimitRedirectionalEndpoints = tc.respectRateLimits
   419  
   420  			mux.HandleFunc("/repos/o/r/actions/artifacts/1/zip", func(w http.ResponseWriter, r *http.Request) {
   421  				testMethod(t, r, "GET")
   422  				http.Redirect(w, r, "https://github.com/artifact", http.StatusMovedPermanently)
   423  			})
   424  
   425  			ctx := context.Background()
   426  			_, resp, _ := client.Actions.DownloadArtifact(ctx, "o", "r", 1, 0)
   427  			if resp.StatusCode != http.StatusMovedPermanently {
   428  				t.Errorf("Actions.DownloadArtifact return status %d, want %d", resp.StatusCode, http.StatusMovedPermanently)
   429  			}
   430  		})
   431  	}
   432  }
   433  
   434  func TestActionsService_DownloadArtifact_StatusMovedPermanently_followRedirects(t *testing.T) {
   435  	t.Parallel()
   436  	tcs := []struct {
   437  		name              string
   438  		respectRateLimits bool
   439  	}{
   440  		{
   441  			name:              "withoutRateLimits",
   442  			respectRateLimits: false,
   443  		},
   444  		{
   445  			name:              "withRateLimits",
   446  			respectRateLimits: true,
   447  		},
   448  	}
   449  
   450  	for _, tc := range tcs {
   451  		tc := tc
   452  		t.Run(tc.name, func(t *testing.T) {
   453  			t.Parallel()
   454  			client, mux, serverURL := setup(t)
   455  			client.RateLimitRedirectionalEndpoints = tc.respectRateLimits
   456  
   457  			mux.HandleFunc("/repos/o/r/actions/artifacts/1/zip", func(w http.ResponseWriter, r *http.Request) {
   458  				testMethod(t, r, "GET")
   459  				redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect")
   460  				http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently)
   461  			})
   462  			mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
   463  				testMethod(t, r, "GET")
   464  				http.Redirect(w, r, "http://github.com/artifact", http.StatusFound)
   465  			})
   466  
   467  			ctx := context.Background()
   468  			url, resp, err := client.Actions.DownloadArtifact(ctx, "o", "r", 1, 1)
   469  			if err != nil {
   470  				t.Errorf("Actions.DownloadArtifact return error: %v", err)
   471  			}
   472  			if resp.StatusCode != http.StatusFound {
   473  				t.Errorf("Actions.DownloadArtifact return status %d, want %d", resp.StatusCode, http.StatusFound)
   474  			}
   475  			want := "http://github.com/artifact"
   476  			if url.String() != want {
   477  				t.Errorf("Actions.DownloadArtifact returned %+v, want %+v", url.String(), want)
   478  			}
   479  		})
   480  	}
   481  }
   482  
   483  func TestActionsService_DownloadArtifact_unexpectedCode(t *testing.T) {
   484  	t.Parallel()
   485  	tcs := []struct {
   486  		name              string
   487  		respectRateLimits bool
   488  	}{
   489  		{
   490  			name:              "withoutRateLimits",
   491  			respectRateLimits: false,
   492  		},
   493  		{
   494  			name:              "withRateLimits",
   495  			respectRateLimits: true,
   496  		},
   497  	}
   498  
   499  	for _, tc := range tcs {
   500  		tc := tc
   501  		t.Run(tc.name, func(t *testing.T) {
   502  			t.Parallel()
   503  			client, mux, serverURL := setup(t)
   504  			client.RateLimitRedirectionalEndpoints = tc.respectRateLimits
   505  
   506  			mux.HandleFunc("/repos/o/r/actions/artifacts/1/zip", func(w http.ResponseWriter, r *http.Request) {
   507  				testMethod(t, r, "GET")
   508  				redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect")
   509  				http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently)
   510  			})
   511  			mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
   512  				testMethod(t, r, "GET")
   513  				w.WriteHeader(http.StatusNoContent)
   514  			})
   515  
   516  			ctx := context.Background()
   517  			url, resp, err := client.Actions.DownloadArtifact(ctx, "o", "r", 1, 1)
   518  			if err == nil {
   519  				t.Fatalf("Actions.DownloadArtifact should return error on unexpected code")
   520  			}
   521  			if !strings.Contains(err.Error(), "unexpected status code") {
   522  				t.Error("Actions.DownloadArtifact should return unexpected status code")
   523  			}
   524  			if got, want := resp.Response.StatusCode, http.StatusNoContent; got != want {
   525  				t.Errorf("Actions.DownloadArtifact return status %d, want %d", got, want)
   526  			}
   527  			if url != nil {
   528  				t.Errorf("Actions.DownloadArtifact return %+v, want nil", url)
   529  			}
   530  		})
   531  	}
   532  }
   533  
   534  func TestActionsService_DeleteArtifact(t *testing.T) {
   535  	t.Parallel()
   536  	client, mux, _ := setup(t)
   537  
   538  	mux.HandleFunc("/repos/o/r/actions/artifacts/1", func(w http.ResponseWriter, r *http.Request) {
   539  		testMethod(t, r, "DELETE")
   540  	})
   541  
   542  	ctx := context.Background()
   543  	_, err := client.Actions.DeleteArtifact(ctx, "o", "r", 1)
   544  	if err != nil {
   545  		t.Errorf("Actions.DeleteArtifact return error: %v", err)
   546  	}
   547  
   548  	const methodName = "DeleteArtifact"
   549  	testBadOptions(t, methodName, func() (err error) {
   550  		_, err = client.Actions.DeleteArtifact(ctx, "\n", "\n", -1)
   551  		return err
   552  	})
   553  
   554  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   555  		return client.Actions.DeleteArtifact(ctx, "o", "r", 1)
   556  	})
   557  }
   558  
   559  func TestActionsService_DeleteArtifact_invalidOwner(t *testing.T) {
   560  	t.Parallel()
   561  	client, _, _ := setup(t)
   562  
   563  	ctx := context.Background()
   564  	_, err := client.Actions.DeleteArtifact(ctx, "%", "r", 1)
   565  	testURLParseError(t, err)
   566  }
   567  
   568  func TestActionsService_DeleteArtifact_invalidRepo(t *testing.T) {
   569  	t.Parallel()
   570  	client, _, _ := setup(t)
   571  
   572  	ctx := context.Background()
   573  	_, err := client.Actions.DeleteArtifact(ctx, "o", "%", 1)
   574  	testURLParseError(t, err)
   575  }
   576  
   577  func TestActionsService_DeleteArtifact_notFound(t *testing.T) {
   578  	t.Parallel()
   579  	client, mux, _ := setup(t)
   580  
   581  	mux.HandleFunc("/repos/o/r/actions/artifacts/1", func(w http.ResponseWriter, r *http.Request) {
   582  		testMethod(t, r, "DELETE")
   583  		w.WriteHeader(http.StatusNotFound)
   584  	})
   585  
   586  	ctx := context.Background()
   587  	resp, err := client.Actions.DeleteArtifact(ctx, "o", "r", 1)
   588  	if err == nil {
   589  		t.Errorf("Expected HTTP 404 response")
   590  	}
   591  	if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
   592  		t.Errorf("Actions.DeleteArtifact return status %d, want %d", got, want)
   593  	}
   594  }
   595  
   596  func TestArtifact_Marshal(t *testing.T) {
   597  	t.Parallel()
   598  	testJSONMarshal(t, &Artifact{}, "{}")
   599  
   600  	u := &Artifact{
   601  		ID:                 Ptr(int64(1)),
   602  		NodeID:             Ptr("nid"),
   603  		Name:               Ptr("n"),
   604  		SizeInBytes:        Ptr(int64(1)),
   605  		URL:                Ptr("u"),
   606  		ArchiveDownloadURL: Ptr("a"),
   607  		Expired:            Ptr(false),
   608  		CreatedAt:          &Timestamp{referenceTime},
   609  		UpdatedAt:          &Timestamp{referenceTime},
   610  		ExpiresAt:          &Timestamp{referenceTime},
   611  		WorkflowRun: &ArtifactWorkflowRun{
   612  			ID:               Ptr(int64(1)),
   613  			RepositoryID:     Ptr(int64(1)),
   614  			HeadRepositoryID: Ptr(int64(1)),
   615  			HeadBranch:       Ptr("b"),
   616  			HeadSHA:          Ptr("s"),
   617  		},
   618  	}
   619  
   620  	want := `{
   621  		"id": 1,
   622  		"node_id": "nid",
   623  		"name": "n",
   624  		"size_in_bytes": 1,
   625  		"url": "u",
   626  		"archive_download_url": "a",
   627  		"expired": false,
   628  		"created_at": ` + referenceTimeStr + `,
   629  		"updated_at": ` + referenceTimeStr + `,
   630  		"expires_at": ` + referenceTimeStr + `,
   631  		"workflow_run": {
   632  			"id": 1,
   633  			"repository_id": 1,
   634  			"head_repository_id": 1,
   635  			"head_branch": "b",
   636  			"head_sha": "s"
   637  		}
   638  	}`
   639  
   640  	testJSONMarshal(t, u, want)
   641  }
   642  
   643  func TestArtifactList_Marshal(t *testing.T) {
   644  	t.Parallel()
   645  	testJSONMarshal(t, &ArtifactList{}, "{}")
   646  
   647  	u := &ArtifactList{
   648  		TotalCount: Ptr(int64(1)),
   649  		Artifacts: []*Artifact{
   650  			{
   651  				ID:                 Ptr(int64(1)),
   652  				NodeID:             Ptr("nid"),
   653  				Name:               Ptr("n"),
   654  				SizeInBytes:        Ptr(int64(1)),
   655  				URL:                Ptr("u"),
   656  				ArchiveDownloadURL: Ptr("a"),
   657  				Expired:            Ptr(false),
   658  				CreatedAt:          &Timestamp{referenceTime},
   659  				UpdatedAt:          &Timestamp{referenceTime},
   660  				ExpiresAt:          &Timestamp{referenceTime},
   661  				WorkflowRun: &ArtifactWorkflowRun{
   662  					ID:               Ptr(int64(1)),
   663  					RepositoryID:     Ptr(int64(1)),
   664  					HeadRepositoryID: Ptr(int64(1)),
   665  					HeadBranch:       Ptr("b"),
   666  					HeadSHA:          Ptr("s"),
   667  				},
   668  			},
   669  		},
   670  	}
   671  
   672  	want := `{
   673  		"total_count": 1,
   674  		"artifacts": [{
   675  			"id": 1,
   676  			"node_id": "nid",
   677  			"name": "n",
   678  			"size_in_bytes": 1,
   679  			"url": "u",
   680  			"archive_download_url": "a",
   681  			"expired": false,
   682  			"created_at": ` + referenceTimeStr + `,
   683  			"updated_at": ` + referenceTimeStr + `,
   684  			"expires_at": ` + referenceTimeStr + `,
   685  			"workflow_run": {
   686  				"id": 1,
   687  				"repository_id": 1,
   688  				"head_repository_id": 1,
   689  				"head_branch": "b",
   690  				"head_sha": "s"
   691  			}
   692  		}]
   693  	}`
   694  
   695  	testJSONMarshal(t, u, want)
   696  }