github.com/google/go-github/v42@v42.0.0/github/actions_workflow_runs_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  	"fmt"
    11  	"net/http"
    12  	"net/url"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/google/go-cmp/cmp"
    17  )
    18  
    19  func TestActionsService_ListWorkflowRunsByID(t *testing.T) {
    20  	client, mux, _, teardown := setup()
    21  	defer teardown()
    22  
    23  	mux.HandleFunc("/repos/o/r/actions/workflows/29679449/runs", func(w http.ResponseWriter, r *http.Request) {
    24  		testMethod(t, r, "GET")
    25  		testFormValues(t, r, values{"per_page": "2", "page": "2"})
    26  		fmt.Fprint(w, `{"total_count":4,"workflow_runs":[{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"},{"id":399444497,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}]}`)
    27  	})
    28  
    29  	opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
    30  	ctx := context.Background()
    31  	runs, _, err := client.Actions.ListWorkflowRunsByID(ctx, "o", "r", 29679449, opts)
    32  	if err != nil {
    33  		t.Errorf("Actions.ListWorkFlowRunsByID returned error: %v", err)
    34  	}
    35  
    36  	want := &WorkflowRuns{
    37  		TotalCount: Int(4),
    38  		WorkflowRuns: []*WorkflowRun{
    39  			{ID: Int64(399444496), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    40  			{ID: Int64(399444497), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    41  		},
    42  	}
    43  	if !cmp.Equal(runs, want) {
    44  		t.Errorf("Actions.ListWorkflowRunsByID returned %+v, want %+v", runs, want)
    45  	}
    46  
    47  	const methodName = "ListWorkflowRunsByID"
    48  	testBadOptions(t, methodName, func() (err error) {
    49  		_, _, err = client.Actions.ListWorkflowRunsByID(ctx, "\n", "\n", 29679449, opts)
    50  		return err
    51  	})
    52  
    53  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    54  		got, resp, err := client.Actions.ListWorkflowRunsByID(ctx, "o", "r", 29679449, opts)
    55  		if got != nil {
    56  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
    57  		}
    58  		return resp, err
    59  	})
    60  }
    61  
    62  func TestActionsService_ListWorkflowRunsFileName(t *testing.T) {
    63  	client, mux, _, teardown := setup()
    64  	defer teardown()
    65  
    66  	mux.HandleFunc("/repos/o/r/actions/workflows/29679449/runs", func(w http.ResponseWriter, r *http.Request) {
    67  		testMethod(t, r, "GET")
    68  		testFormValues(t, r, values{"per_page": "2", "page": "2"})
    69  		fmt.Fprint(w, `{"total_count":4,"workflow_runs":[{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"},{"id":399444497,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}]}`)
    70  	})
    71  
    72  	opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
    73  	ctx := context.Background()
    74  	runs, _, err := client.Actions.ListWorkflowRunsByFileName(ctx, "o", "r", "29679449", opts)
    75  	if err != nil {
    76  		t.Errorf("Actions.ListWorkFlowRunsByFileName returned error: %v", err)
    77  	}
    78  
    79  	want := &WorkflowRuns{
    80  		TotalCount: Int(4),
    81  		WorkflowRuns: []*WorkflowRun{
    82  			{ID: Int64(399444496), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    83  			{ID: Int64(399444497), RunNumber: Int(296), CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)}},
    84  		},
    85  	}
    86  	if !cmp.Equal(runs, want) {
    87  		t.Errorf("Actions.ListWorkflowRunsByFileName returned %+v, want %+v", runs, want)
    88  	}
    89  
    90  	const methodName = "ListWorkflowRunsByFileName"
    91  	testBadOptions(t, methodName, func() (err error) {
    92  		_, _, err = client.Actions.ListWorkflowRunsByFileName(ctx, "\n", "\n", "29679449", opts)
    93  		return err
    94  	})
    95  
    96  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
    97  		got, resp, err := client.Actions.ListWorkflowRunsByFileName(ctx, "o", "r", "29679449", opts)
    98  		if got != nil {
    99  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   100  		}
   101  		return resp, err
   102  	})
   103  }
   104  
   105  func TestActionsService_GetWorkflowRunByID(t *testing.T) {
   106  	client, mux, _, teardown := setup()
   107  	defer teardown()
   108  
   109  	mux.HandleFunc("/repos/o/r/actions/runs/29679449", func(w http.ResponseWriter, r *http.Request) {
   110  		testMethod(t, r, "GET")
   111  		fmt.Fprint(w, `{"id":399444496,"run_number":296,"created_at":"2019-01-02T15:04:05Z","updated_at":"2020-01-02T15:04:05Z"}}`)
   112  	})
   113  
   114  	ctx := context.Background()
   115  	runs, _, err := client.Actions.GetWorkflowRunByID(ctx, "o", "r", 29679449)
   116  	if err != nil {
   117  		t.Errorf("Actions.GetWorkflowRunByID returned error: %v", err)
   118  	}
   119  
   120  	want := &WorkflowRun{
   121  		ID:        Int64(399444496),
   122  		RunNumber: Int(296),
   123  		CreatedAt: &Timestamp{time.Date(2019, time.January, 02, 15, 04, 05, 0, time.UTC)},
   124  		UpdatedAt: &Timestamp{time.Date(2020, time.January, 02, 15, 04, 05, 0, time.UTC)},
   125  	}
   126  
   127  	if !cmp.Equal(runs, want) {
   128  		t.Errorf("Actions.GetWorkflowRunByID returned %+v, want %+v", runs, want)
   129  	}
   130  
   131  	const methodName = "GetWorkflowRunByID"
   132  	testBadOptions(t, methodName, func() (err error) {
   133  		_, _, err = client.Actions.GetWorkflowRunByID(ctx, "\n", "\n", 29679449)
   134  		return err
   135  	})
   136  
   137  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   138  		got, resp, err := client.Actions.GetWorkflowRunByID(ctx, "o", "r", 29679449)
   139  		if got != nil {
   140  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   141  		}
   142  		return resp, err
   143  	})
   144  }
   145  
   146  func TestActionsService_RerunWorkflowRunByID(t *testing.T) {
   147  	client, mux, _, teardown := setup()
   148  	defer teardown()
   149  
   150  	mux.HandleFunc("/repos/o/r/actions/runs/3434/rerun", func(w http.ResponseWriter, r *http.Request) {
   151  		testMethod(t, r, "POST")
   152  		w.WriteHeader(http.StatusCreated)
   153  	})
   154  
   155  	ctx := context.Background()
   156  	resp, err := client.Actions.RerunWorkflowByID(ctx, "o", "r", 3434)
   157  	if err != nil {
   158  		t.Errorf("Actions.RerunWorkflowByID returned error: %v", err)
   159  	}
   160  	if resp.StatusCode != http.StatusCreated {
   161  		t.Errorf("Actions.RerunWorkflowRunByID returned status: %d, want %d", resp.StatusCode, http.StatusCreated)
   162  	}
   163  
   164  	const methodName = "RerunWorkflowByID"
   165  	testBadOptions(t, methodName, func() (err error) {
   166  		_, err = client.Actions.RerunWorkflowByID(ctx, "\n", "\n", 3434)
   167  		return err
   168  	})
   169  
   170  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   171  		return client.Actions.RerunWorkflowByID(ctx, "o", "r", 3434)
   172  	})
   173  }
   174  
   175  func TestActionsService_CancelWorkflowRunByID(t *testing.T) {
   176  	client, mux, _, teardown := setup()
   177  	defer teardown()
   178  
   179  	mux.HandleFunc("/repos/o/r/actions/runs/3434/cancel", func(w http.ResponseWriter, r *http.Request) {
   180  		testMethod(t, r, "POST")
   181  		w.WriteHeader(http.StatusAccepted)
   182  	})
   183  
   184  	ctx := context.Background()
   185  	resp, err := client.Actions.CancelWorkflowRunByID(ctx, "o", "r", 3434)
   186  	if _, ok := err.(*AcceptedError); !ok {
   187  		t.Errorf("Actions.CancelWorkflowRunByID returned error: %v (want AcceptedError)", err)
   188  	}
   189  	if resp.StatusCode != http.StatusAccepted {
   190  		t.Errorf("Actions.CancelWorkflowRunByID returned status: %d, want %d", resp.StatusCode, http.StatusAccepted)
   191  	}
   192  
   193  	const methodName = "CancelWorkflowRunByID"
   194  	testBadOptions(t, methodName, func() (err error) {
   195  		_, err = client.Actions.CancelWorkflowRunByID(ctx, "\n", "\n", 3434)
   196  		return err
   197  	})
   198  
   199  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   200  		return client.Actions.CancelWorkflowRunByID(ctx, "o", "r", 3434)
   201  	})
   202  }
   203  
   204  func TestActionsService_GetWorkflowRunLogs(t *testing.T) {
   205  	client, mux, _, teardown := setup()
   206  	defer teardown()
   207  
   208  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   209  		testMethod(t, r, "GET")
   210  		http.Redirect(w, r, "http://github.com/a", http.StatusFound)
   211  	})
   212  
   213  	ctx := context.Background()
   214  	url, resp, err := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, true)
   215  	if err != nil {
   216  		t.Errorf("Actions.GetWorkflowRunLogs returned error: %v", err)
   217  	}
   218  	if resp.StatusCode != http.StatusFound {
   219  		t.Errorf("Actions.GetWorkflowRunLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound)
   220  	}
   221  	want := "http://github.com/a"
   222  	if url.String() != want {
   223  		t.Errorf("Actions.GetWorkflowRunLogs returned %+v, want %+v", url.String(), want)
   224  	}
   225  
   226  	const methodName = "GetWorkflowRunLogs"
   227  	testBadOptions(t, methodName, func() (err error) {
   228  		_, _, err = client.Actions.GetWorkflowRunLogs(ctx, "\n", "\n", 399444496, true)
   229  		return err
   230  	})
   231  }
   232  
   233  func TestActionsService_GetWorkflowRunLogs_StatusMovedPermanently_dontFollowRedirects(t *testing.T) {
   234  	client, mux, _, teardown := setup()
   235  	defer teardown()
   236  
   237  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   238  		testMethod(t, r, "GET")
   239  		http.Redirect(w, r, "http://github.com/a", http.StatusMovedPermanently)
   240  	})
   241  
   242  	ctx := context.Background()
   243  	_, resp, _ := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, false)
   244  	if resp.StatusCode != http.StatusMovedPermanently {
   245  		t.Errorf("Actions.GetWorkflowJobLogs returned status: %d, want %d", resp.StatusCode, http.StatusMovedPermanently)
   246  	}
   247  }
   248  
   249  func TestActionsService_GetWorkflowRunLogs_StatusMovedPermanently_followRedirects(t *testing.T) {
   250  	client, mux, serverURL, teardown := setup()
   251  	defer teardown()
   252  
   253  	// Mock a redirect link, which leads to an archive link
   254  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   255  		testMethod(t, r, "GET")
   256  		redirectURL, _ := url.Parse(serverURL + baseURLPath + "/redirect")
   257  		http.Redirect(w, r, redirectURL.String(), http.StatusMovedPermanently)
   258  	})
   259  
   260  	mux.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
   261  		testMethod(t, r, "GET")
   262  		http.Redirect(w, r, "http://github.com/a", http.StatusFound)
   263  	})
   264  
   265  	ctx := context.Background()
   266  	url, resp, err := client.Actions.GetWorkflowRunLogs(ctx, "o", "r", 399444496, true)
   267  	if err != nil {
   268  		t.Errorf("Actions.GetWorkflowJobLogs returned error: %v", err)
   269  	}
   270  
   271  	if resp.StatusCode != http.StatusFound {
   272  		t.Errorf("Actions.GetWorkflowJobLogs returned status: %d, want %d", resp.StatusCode, http.StatusFound)
   273  	}
   274  
   275  	want := "http://github.com/a"
   276  	if url.String() != want {
   277  		t.Errorf("Actions.GetWorkflowJobLogs returned %+v, want %+v", url.String(), want)
   278  	}
   279  
   280  	const methodName = "GetWorkflowRunLogs"
   281  	testBadOptions(t, methodName, func() (err error) {
   282  		_, _, err = client.Actions.GetWorkflowRunLogs(ctx, "\n", "\n", 399444496, true)
   283  		return err
   284  	})
   285  }
   286  
   287  func TestActionService_ListRepositoryWorkflowRuns(t *testing.T) {
   288  	client, mux, _, teardown := setup()
   289  	defer teardown()
   290  
   291  	mux.HandleFunc("/repos/o/r/actions/runs", func(w http.ResponseWriter, r *http.Request) {
   292  		testMethod(t, r, "GET")
   293  		testFormValues(t, r, values{"per_page": "2", "page": "2"})
   294  		fmt.Fprint(w, `{"total_count":2,
   295  		"workflow_runs":[
   296  			{"id":298499444,"run_number":301,"created_at":"2020-04-11T11:14:54Z","updated_at":"2020-04-11T11:14:54Z"},
   297  			{"id":298499445,"run_number":302,"created_at":"2020-04-11T11:14:54Z","updated_at":"2020-04-11T11:14:54Z"}]}`)
   298  	})
   299  
   300  	opts := &ListWorkflowRunsOptions{ListOptions: ListOptions{Page: 2, PerPage: 2}}
   301  	ctx := context.Background()
   302  	runs, _, err := client.Actions.ListRepositoryWorkflowRuns(ctx, "o", "r", opts)
   303  
   304  	if err != nil {
   305  		t.Errorf("Actions.ListRepositoryWorkflowRuns returned error: %v", err)
   306  	}
   307  
   308  	expected := &WorkflowRuns{
   309  		TotalCount: Int(2),
   310  		WorkflowRuns: []*WorkflowRun{
   311  			{ID: Int64(298499444), RunNumber: Int(301), CreatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}},
   312  			{ID: Int64(298499445), RunNumber: Int(302), CreatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}, UpdatedAt: &Timestamp{time.Date(2020, time.April, 11, 11, 14, 54, 0, time.UTC)}},
   313  		},
   314  	}
   315  
   316  	if !cmp.Equal(runs, expected) {
   317  		t.Errorf("Actions.ListRepositoryWorkflowRuns returned %+v, want %+v", runs, expected)
   318  	}
   319  
   320  	const methodName = "ListRepositoryWorkflowRuns"
   321  	testBadOptions(t, methodName, func() (err error) {
   322  		_, _, err = client.Actions.ListRepositoryWorkflowRuns(ctx, "\n", "\n", opts)
   323  
   324  		return err
   325  	})
   326  
   327  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   328  		got, resp, err := client.Actions.ListRepositoryWorkflowRuns(ctx, "o", "r", opts)
   329  
   330  		if got != nil {
   331  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   332  		}
   333  		return resp, err
   334  	})
   335  }
   336  
   337  func TestActionService_DeleteWorkflowRun(t *testing.T) {
   338  	client, mux, _, teardown := setup()
   339  	defer teardown()
   340  
   341  	mux.HandleFunc("/repos/o/r/actions/runs/399444496", func(w http.ResponseWriter, r *http.Request) {
   342  		testMethod(t, r, "DELETE")
   343  
   344  		w.WriteHeader(http.StatusNoContent)
   345  	})
   346  
   347  	ctx := context.Background()
   348  	if _, err := client.Actions.DeleteWorkflowRun(ctx, "o", "r", 399444496); err != nil {
   349  		t.Errorf("DeleteWorkflowRun returned error: %v", err)
   350  	}
   351  
   352  	const methodName = "DeleteWorkflowRun"
   353  	testBadOptions(t, methodName, func() (err error) {
   354  		_, err = client.Actions.DeleteWorkflowRun(ctx, "\n", "\n", 399444496)
   355  		return err
   356  	})
   357  
   358  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   359  		return client.Actions.DeleteWorkflowRun(ctx, "o", "r", 399444496)
   360  	})
   361  }
   362  
   363  func TestActionService_DeleteWorkflowRunLogs(t *testing.T) {
   364  	client, mux, _, teardown := setup()
   365  	defer teardown()
   366  
   367  	mux.HandleFunc("/repos/o/r/actions/runs/399444496/logs", func(w http.ResponseWriter, r *http.Request) {
   368  		testMethod(t, r, "DELETE")
   369  
   370  		w.WriteHeader(http.StatusNoContent)
   371  	})
   372  
   373  	ctx := context.Background()
   374  	if _, err := client.Actions.DeleteWorkflowRunLogs(ctx, "o", "r", 399444496); err != nil {
   375  		t.Errorf("DeleteWorkflowRunLogs returned error: %v", err)
   376  	}
   377  
   378  	const methodName = "DeleteWorkflowRunLogs"
   379  	testBadOptions(t, methodName, func() (err error) {
   380  		_, err = client.Actions.DeleteWorkflowRunLogs(ctx, "\n", "\n", 399444496)
   381  		return err
   382  	})
   383  
   384  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   385  		return client.Actions.DeleteWorkflowRunLogs(ctx, "o", "r", 399444496)
   386  	})
   387  }
   388  
   389  func TestActionsService_GetWorkflowRunUsageByID(t *testing.T) {
   390  	client, mux, _, teardown := setup()
   391  	defer teardown()
   392  
   393  	mux.HandleFunc("/repos/o/r/actions/runs/29679449/timing", func(w http.ResponseWriter, r *http.Request) {
   394  		testMethod(t, r, "GET")
   395  		fmt.Fprint(w, `{"billable":{"UBUNTU":{"total_ms":180000,"jobs":1,"job_runs":[{"job_id":1,"duration_ms":60000}]},"MACOS":{"total_ms":240000,"jobs":2,"job_runs":[{"job_id":2,"duration_ms":30000},{"job_id":3,"duration_ms":10000}]},"WINDOWS":{"total_ms":300000,"jobs":2}},"run_duration_ms":500000}`)
   396  	})
   397  
   398  	ctx := context.Background()
   399  	workflowRunUsage, _, err := client.Actions.GetWorkflowRunUsageByID(ctx, "o", "r", 29679449)
   400  	if err != nil {
   401  		t.Errorf("Actions.GetWorkflowRunUsageByID returned error: %v", err)
   402  	}
   403  
   404  	want := &WorkflowRunUsage{
   405  		Billable: &WorkflowRunEnvironment{
   406  			Ubuntu: &WorkflowRunBill{
   407  				TotalMS: Int64(180000),
   408  				Jobs:    Int(1),
   409  				JobRuns: []*WorkflowRunJobRun{
   410  					{
   411  						JobID:      Int(1),
   412  						DurationMS: Int64(60000),
   413  					},
   414  				},
   415  			},
   416  			MacOS: &WorkflowRunBill{
   417  				TotalMS: Int64(240000),
   418  				Jobs:    Int(2),
   419  				JobRuns: []*WorkflowRunJobRun{
   420  					{
   421  						JobID:      Int(2),
   422  						DurationMS: Int64(30000),
   423  					},
   424  					{
   425  						JobID:      Int(3),
   426  						DurationMS: Int64(10000),
   427  					},
   428  				},
   429  			},
   430  			Windows: &WorkflowRunBill{
   431  				TotalMS: Int64(300000),
   432  				Jobs:    Int(2),
   433  			},
   434  		},
   435  		RunDurationMS: Int64(500000),
   436  	}
   437  
   438  	if !cmp.Equal(workflowRunUsage, want) {
   439  		t.Errorf("Actions.GetWorkflowRunUsageByID returned %+v, want %+v", workflowRunUsage, want)
   440  	}
   441  
   442  	const methodName = "GetWorkflowRunUsageByID"
   443  	testBadOptions(t, methodName, func() (err error) {
   444  		_, _, err = client.Actions.GetWorkflowRunUsageByID(ctx, "\n", "\n", 29679449)
   445  		return err
   446  	})
   447  
   448  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   449  		got, resp, err := client.Actions.GetWorkflowRunUsageByID(ctx, "o", "r", 29679449)
   450  		if got != nil {
   451  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   452  		}
   453  		return resp, err
   454  	})
   455  }
   456  
   457  func TestWorkflowRun_Marshal(t *testing.T) {
   458  	testJSONMarshal(t, &WorkflowRun{}, "{}")
   459  
   460  	u := &WorkflowRun{
   461  		ID:         Int64(1),
   462  		Name:       String("n"),
   463  		NodeID:     String("nid"),
   464  		HeadBranch: String("hb"),
   465  		HeadSHA:    String("hs"),
   466  		RunNumber:  Int(1),
   467  		RunAttempt: Int(1),
   468  		Event:      String("e"),
   469  		Status:     String("s"),
   470  		Conclusion: String("c"),
   471  		WorkflowID: Int64(1),
   472  		URL:        String("u"),
   473  		HTMLURL:    String("h"),
   474  		PullRequests: []*PullRequest{
   475  			{
   476  				URL:    String("u"),
   477  				ID:     Int64(1),
   478  				Number: Int(1),
   479  				Head: &PullRequestBranch{
   480  					Ref: String("r"),
   481  					SHA: String("s"),
   482  					Repo: &Repository{
   483  						ID:   Int64(1),
   484  						URL:  String("s"),
   485  						Name: String("n"),
   486  					},
   487  				},
   488  				Base: &PullRequestBranch{
   489  					Ref: String("r"),
   490  					SHA: String("s"),
   491  					Repo: &Repository{
   492  						ID:   Int64(1),
   493  						URL:  String("u"),
   494  						Name: String("n"),
   495  					},
   496  				},
   497  			},
   498  		},
   499  		CreatedAt:          &Timestamp{referenceTime},
   500  		UpdatedAt:          &Timestamp{referenceTime},
   501  		RunStartedAt:       &Timestamp{referenceTime},
   502  		JobsURL:            String("j"),
   503  		LogsURL:            String("l"),
   504  		CheckSuiteURL:      String("c"),
   505  		ArtifactsURL:       String("a"),
   506  		CancelURL:          String("c"),
   507  		RerunURL:           String("r"),
   508  		PreviousAttemptURL: String("p"),
   509  		HeadCommit: &HeadCommit{
   510  			Message: String("m"),
   511  			Author: &CommitAuthor{
   512  				Name:  String("n"),
   513  				Email: String("e"),
   514  				Login: String("l"),
   515  			},
   516  			URL:       String("u"),
   517  			Distinct:  Bool(false),
   518  			SHA:       String("s"),
   519  			ID:        String("i"),
   520  			TreeID:    String("tid"),
   521  			Timestamp: &Timestamp{referenceTime},
   522  			Committer: &CommitAuthor{
   523  				Name:  String("n"),
   524  				Email: String("e"),
   525  				Login: String("l"),
   526  			},
   527  		},
   528  		WorkflowURL: String("w"),
   529  		Repository: &Repository{
   530  			ID:   Int64(1),
   531  			URL:  String("u"),
   532  			Name: String("n"),
   533  		},
   534  		HeadRepository: &Repository{
   535  			ID:   Int64(1),
   536  			URL:  String("u"),
   537  			Name: String("n"),
   538  		},
   539  	}
   540  
   541  	want := `{
   542  		"id": 1,
   543  		"name": "n",
   544  		"node_id": "nid",
   545  		"head_branch": "hb",
   546  		"head_sha": "hs",
   547  		"run_number": 1,
   548  		"run_attempt": 1,
   549  		"event": "e",
   550  		"status": "s",
   551  		"conclusion": "c",
   552  		"workflow_id": 1,
   553  		"url": "u",
   554  		"html_url": "h",
   555  		"pull_requests": [
   556  			{
   557  				"id":1,
   558  				"number":1,
   559  				"url":"u",
   560  				"head":{
   561  					"ref":"r",
   562  					"sha":"s",
   563  					"repo": {
   564  						"id":1,
   565  						"name":"n",
   566  						"url":"s"
   567  						}
   568  					},
   569  					"base": {
   570  						"ref":"r",
   571  						"sha":"s",
   572  						"repo": {
   573  							"id":1,
   574  							"name":"n",
   575  							"url":"u"
   576  						}
   577  					}
   578  			}
   579  		],
   580  		"created_at": ` + referenceTimeStr + `,
   581  		"updated_at": ` + referenceTimeStr + `,
   582  		"run_started_at": ` + referenceTimeStr + `,
   583  		"jobs_url": "j",
   584  		"logs_url": "l",
   585  		"check_suite_url": "c",
   586  		"artifacts_url": "a",
   587  		"cancel_url": "c",
   588  		"rerun_url": "r",
   589  		"previous_attempt_url": "p",
   590  		"head_commit": {
   591  			"message": "m",
   592  			"author": {
   593  				"name": "n",
   594  				"email": "e",
   595  				"username": "l"
   596  			},
   597  			"url": "u",
   598  			"distinct": false,
   599  			"sha": "s",
   600  			"id": "i",
   601  			"tree_id": "tid",
   602  			"timestamp": ` + referenceTimeStr + `,
   603  			"committer": {
   604  				"name": "n",
   605  				"email": "e",
   606  				"username": "l"
   607  			}
   608  		},
   609  		"workflow_url": "w",
   610  		"repository": {
   611  			"id": 1,
   612  			"url": "u",
   613  			"name": "n"
   614  		},
   615  		"head_repository": {
   616  			"id": 1,
   617  			"url": "u",
   618  			"name": "n"
   619  		}
   620  	}`
   621  
   622  	testJSONMarshal(t, u, want)
   623  }
   624  
   625  func TestWorkflowRuns_Marshal(t *testing.T) {
   626  	testJSONMarshal(t, &WorkflowRuns{}, "{}")
   627  
   628  	u := &WorkflowRuns{
   629  		TotalCount: Int(1),
   630  		WorkflowRuns: []*WorkflowRun{
   631  			{
   632  				ID:         Int64(1),
   633  				Name:       String("n"),
   634  				NodeID:     String("nid"),
   635  				HeadBranch: String("hb"),
   636  				HeadSHA:    String("hs"),
   637  				RunNumber:  Int(1),
   638  				RunAttempt: Int(1),
   639  				Event:      String("e"),
   640  				Status:     String("s"),
   641  				Conclusion: String("c"),
   642  				WorkflowID: Int64(1),
   643  				URL:        String("u"),
   644  				HTMLURL:    String("h"),
   645  				PullRequests: []*PullRequest{
   646  					{
   647  						URL:    String("u"),
   648  						ID:     Int64(1),
   649  						Number: Int(1),
   650  						Head: &PullRequestBranch{
   651  							Ref: String("r"),
   652  							SHA: String("s"),
   653  							Repo: &Repository{
   654  								ID:   Int64(1),
   655  								URL:  String("s"),
   656  								Name: String("n"),
   657  							},
   658  						},
   659  						Base: &PullRequestBranch{
   660  							Ref: String("r"),
   661  							SHA: String("s"),
   662  							Repo: &Repository{
   663  								ID:   Int64(1),
   664  								URL:  String("u"),
   665  								Name: String("n"),
   666  							},
   667  						},
   668  					},
   669  				},
   670  				CreatedAt:          &Timestamp{referenceTime},
   671  				UpdatedAt:          &Timestamp{referenceTime},
   672  				RunStartedAt:       &Timestamp{referenceTime},
   673  				JobsURL:            String("j"),
   674  				LogsURL:            String("l"),
   675  				CheckSuiteURL:      String("c"),
   676  				ArtifactsURL:       String("a"),
   677  				CancelURL:          String("c"),
   678  				RerunURL:           String("r"),
   679  				PreviousAttemptURL: String("p"),
   680  				HeadCommit: &HeadCommit{
   681  					Message: String("m"),
   682  					Author: &CommitAuthor{
   683  						Name:  String("n"),
   684  						Email: String("e"),
   685  						Login: String("l"),
   686  					},
   687  					URL:       String("u"),
   688  					Distinct:  Bool(false),
   689  					SHA:       String("s"),
   690  					ID:        String("i"),
   691  					TreeID:    String("tid"),
   692  					Timestamp: &Timestamp{referenceTime},
   693  					Committer: &CommitAuthor{
   694  						Name:  String("n"),
   695  						Email: String("e"),
   696  						Login: String("l"),
   697  					},
   698  				},
   699  				WorkflowURL: String("w"),
   700  				Repository: &Repository{
   701  					ID:   Int64(1),
   702  					URL:  String("u"),
   703  					Name: String("n"),
   704  				},
   705  				HeadRepository: &Repository{
   706  					ID:   Int64(1),
   707  					URL:  String("u"),
   708  					Name: String("n"),
   709  				},
   710  			},
   711  		},
   712  	}
   713  
   714  	want := `{
   715  		"total_count": 1,
   716  		"workflow_runs": [
   717  			{
   718  				"id": 1,
   719  				"name": "n",
   720  				"node_id": "nid",
   721  				"head_branch": "hb",
   722  				"head_sha": "hs",
   723  				"run_number": 1,
   724  				"run_attempt": 1,
   725  				"event": "e",
   726  				"status": "s",
   727  				"conclusion": "c",
   728  				"workflow_id": 1,
   729  				"url": "u",
   730  				"html_url": "h",
   731  				"pull_requests": [
   732  					{
   733  						"id":1,
   734  						"number":1,
   735  						"url":"u",
   736  						"head":{
   737  							"ref":"r",
   738  							"sha":"s",
   739  							"repo": {
   740  								"id":1,
   741  								"name":"n",
   742  								"url":"s"
   743  								}
   744  							},
   745  							"base": {
   746  								"ref":"r",
   747  								"sha":"s",
   748  								"repo": {
   749  									"id":1,
   750  									"name":"n",
   751  									"url":"u"
   752  								}
   753  							}
   754  					}
   755  				],
   756  				"created_at": ` + referenceTimeStr + `,
   757  				"updated_at": ` + referenceTimeStr + `,
   758  				"run_started_at": ` + referenceTimeStr + `,
   759  				"jobs_url": "j",
   760  				"logs_url": "l",
   761  				"check_suite_url": "c",
   762  				"artifacts_url": "a",
   763  				"cancel_url": "c",
   764  				"rerun_url": "r",
   765  				"previous_attempt_url": "p",
   766  				"head_commit": {
   767  					"message": "m",
   768  					"author": {
   769  						"name": "n",
   770  						"email": "e",
   771  						"username": "l"
   772  					},
   773  					"url": "u",
   774  					"distinct": false,
   775  					"sha": "s",
   776  					"id": "i",
   777  					"tree_id": "tid",
   778  					"timestamp": ` + referenceTimeStr + `,
   779  					"committer": {
   780  						"name": "n",
   781  						"email": "e",
   782  						"username": "l"
   783  					}
   784  				},
   785  				"workflow_url": "w",
   786  				"repository": {
   787  					"id": 1,
   788  					"url": "u",
   789  					"name": "n"
   790  				},
   791  				"head_repository": {
   792  					"id": 1,
   793  					"url": "u",
   794  					"name": "n"
   795  				}
   796  			}
   797  		]
   798  	}`
   799  
   800  	testJSONMarshal(t, u, want)
   801  }
   802  
   803  func TestWorkflowRunBill_Marshal(t *testing.T) {
   804  	testJSONMarshal(t, &WorkflowRunBill{}, "{}")
   805  
   806  	u := &WorkflowRunBill{
   807  		TotalMS: Int64(1),
   808  		Jobs:    Int(1),
   809  	}
   810  
   811  	want := `{
   812  		"total_ms": 1,
   813  		"jobs": 1
   814  	}`
   815  
   816  	testJSONMarshal(t, u, want)
   817  }
   818  
   819  func TestWorkflowRunEnvironment_Marshal(t *testing.T) {
   820  	testJSONMarshal(t, &WorkflowRunEnvironment{}, "{}")
   821  
   822  	u := &WorkflowRunEnvironment{
   823  		Ubuntu: &WorkflowRunBill{
   824  			TotalMS: Int64(1),
   825  			Jobs:    Int(1),
   826  		},
   827  		MacOS: &WorkflowRunBill{
   828  			TotalMS: Int64(1),
   829  			Jobs:    Int(1),
   830  		},
   831  		Windows: &WorkflowRunBill{
   832  			TotalMS: Int64(1),
   833  			Jobs:    Int(1),
   834  		},
   835  	}
   836  
   837  	want := `{
   838  		"UBUNTU": {
   839  			"total_ms": 1,
   840  			"jobs": 1
   841  		},
   842  		"MACOS": {
   843  			"total_ms": 1,
   844  			"jobs": 1
   845  		},
   846  		"WINDOWS": {
   847  			"total_ms": 1,
   848  			"jobs": 1
   849  		}
   850  	}`
   851  
   852  	testJSONMarshal(t, u, want)
   853  }
   854  
   855  func TestWorkflowRunUsage_Marshal(t *testing.T) {
   856  	testJSONMarshal(t, &WorkflowRunUsage{}, "{}")
   857  
   858  	u := &WorkflowRunUsage{
   859  		Billable: &WorkflowRunEnvironment{
   860  			Ubuntu: &WorkflowRunBill{
   861  				TotalMS: Int64(1),
   862  				Jobs:    Int(1),
   863  			},
   864  			MacOS: &WorkflowRunBill{
   865  				TotalMS: Int64(1),
   866  				Jobs:    Int(1),
   867  			},
   868  			Windows: &WorkflowRunBill{
   869  				TotalMS: Int64(1),
   870  				Jobs:    Int(1),
   871  			},
   872  		},
   873  		RunDurationMS: Int64(1),
   874  	}
   875  
   876  	want := `{
   877  		"billable": {
   878  			"UBUNTU": {
   879  				"total_ms": 1,
   880  				"jobs": 1
   881  			},
   882  			"MACOS": {
   883  				"total_ms": 1,
   884  				"jobs": 1
   885  			},
   886  			"WINDOWS": {
   887  				"total_ms": 1,
   888  				"jobs": 1
   889  			}
   890  		},
   891  		"run_duration_ms": 1
   892  	}`
   893  
   894  	testJSONMarshal(t, u, want)
   895  }