github.com/google/go-github/v70@v70.0.0/github/enterprise_manage_ghes_config_test.go (about)

     1  // Copyright 2025 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  	"encoding/json"
    11  	"fmt"
    12  	"net/http"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/google/go-cmp/cmp"
    17  )
    18  
    19  func TestEnterpriseService_Settings(t *testing.T) {
    20  	t.Parallel()
    21  	client, mux, _ := setup(t)
    22  
    23  	mux.HandleFunc("/manage/v1/config/settings", func(w http.ResponseWriter, r *http.Request) {
    24  		testMethod(t, r, "GET")
    25  		fmt.Fprint(w, `{
    26  			"private_mode": false,
    27  			"public_pages": false,
    28  			"subdomain_isolation": true,
    29  			"signup_enabled": false,
    30  			"github_hostname": "ghe.local",
    31  			"identicons_host": "dotcom",
    32  			"http_proxy": null,
    33  			"auth_mode": "default",
    34  			"expire_sessions": false,
    35  			"admin_password": null,
    36  			"configuration_id": 1401777404,
    37  			"configuration_run_count": 4,
    38  			"avatar": {
    39  				"enabled": false,
    40  				"uri": ""
    41  			},
    42  			"customer": {
    43  				"name": "GitHub",
    44  				"email": "stannis",
    45  				"uuid": "af6cac80-e4e1-012e-d822-1231380e52e9",
    46  				"secret_key_data": "-",
    47  				"public_key_data": "-"
    48  			},
    49  			"license": {
    50  				"seats": 0,
    51  				"evaluation": false,
    52  				"perpetual": false,
    53  				"unlimited_seating": true,
    54  				"support_key": "ssh-rsa AAAAB3N....",
    55  				"ssh_allowed": true,
    56  				"cluster_support": false,
    57  				"expire_at": "2018-01-01T00:00:00-00:00"
    58  			},
    59  			"github_ssl": {
    60  				"enabled": false,
    61  				"cert": null,
    62  				"key": null
    63  			},
    64  			"ldap": {
    65  				"host": null,
    66  				"port": 0,
    67  				"base": [],
    68  				"uid": null,
    69  				"bind_dn": null,
    70  				"password": null,
    71  				"method": "Plain",
    72  				"search_strategy": "detect",
    73  				"user_groups": [],
    74  				"admin_group": null,
    75  				"virtual_attribute_enabled": false,
    76  				"recursive_group_search": false,
    77  				"posix_support": true,
    78  				"user_sync_emails": false,
    79  				"user_sync_keys": false,
    80  				"user_sync_interval": 4,
    81  				"team_sync_interval": 4,
    82  				"sync_enabled": false,
    83  				"reconciliation": {
    84  				"user": null,
    85  				"org": null
    86  				},
    87  				"profile": {
    88  				"uid": "uid",
    89  				"name": null,
    90  				"mail": null,
    91  				"key": null
    92  				}
    93  			},
    94  			"cas": {
    95  				"url": null
    96  			},
    97  			"saml": {
    98  				"sso_url": null,
    99  				"certificate": null,
   100  				"certificate_path": null,
   101  				"issuer": null,
   102  				"idp_initiated_sso": false,
   103  				"disable_admin_demote": false
   104  			},
   105  			"github_oauth": {
   106  				"client_id": "12313412",
   107  				"client_secret": "kj123131132",
   108  				"organization_name": "Homestar Runners",
   109  				"organization_team": "homestarrunners/characters"
   110  			},
   111  			"smtp": {
   112  				"enabled": true,
   113  				"address": "smtp.example.com",
   114  				"authentication": "plain",
   115  				"port": "1234",
   116  				"domain": "blah",
   117  				"username": "foo",
   118  				"user_name": "mr_foo",
   119  				"enable_starttls_auto": true,
   120  				"password": "bar",
   121  				"discard-to-noreply-address": true,
   122  				"support_address": "enterprise@github.com",
   123  				"support_address_type": "email",
   124  				"noreply_address": "noreply@github.com"
   125  			},
   126  			"ntp": {
   127  				"primary_server": "0.pool.ntp.org",
   128  				"secondary_server": "1.pool.ntp.org"
   129  			},
   130  			"timezone": null,
   131  			"snmp": {
   132  				"enabled": false,
   133  				"community": ""
   134  			},
   135  			"syslog": {
   136  				"enabled": false,
   137  				"server": null,
   138  				"protocol_name": "udp"
   139  			},
   140  			"assets": null,
   141  			"pages": {
   142  				"enabled": true
   143  			},
   144  			"collectd": {
   145  				"enabled": false,
   146  				"server": null,
   147  				"port": 0,
   148  				"encryption": null,
   149  				"username": null,
   150  				"password": null
   151  			},
   152  			"mapping": {
   153  				"enabled": true,
   154  				"tileserver": null,
   155  				"basemap": "company.map-qsz2zrvs",
   156  				"token": null
   157  			},
   158  			"load_balancer": null
   159  			}`)
   160  	})
   161  
   162  	ctx := context.Background()
   163  	configSettings, _, err := client.Enterprise.Settings(ctx)
   164  	if err != nil {
   165  		t.Errorf("Enterprise.Settings returned error: %v", err)
   166  	}
   167  
   168  	want := &ConfigSettings{
   169  		PrivateMode:           Ptr(false),
   170  		PublicPages:           Ptr(false),
   171  		SubdomainIsolation:    Ptr(true),
   172  		SignupEnabled:         Ptr(false),
   173  		GithubHostname:        Ptr("ghe.local"),
   174  		IdenticonsHost:        Ptr("dotcom"),
   175  		HTTPProxy:             nil,
   176  		AuthMode:              Ptr("default"),
   177  		ExpireSessions:        Ptr(false),
   178  		AdminPassword:         nil,
   179  		ConfigurationID:       Ptr(int64(1401777404)),
   180  		ConfigurationRunCount: Ptr(4),
   181  		Avatar: &ConfigSettingsAvatar{
   182  			Enabled: Ptr(false),
   183  			URI:     Ptr(""),
   184  		},
   185  		Customer: &ConfigSettingsCustomer{
   186  			Name:          Ptr("GitHub"),
   187  			Email:         Ptr("stannis"),
   188  			UUID:          Ptr("af6cac80-e4e1-012e-d822-1231380e52e9"),
   189  			Secret:        nil,
   190  			PublicKeyData: Ptr("-"),
   191  		},
   192  		License: &ConfigSettingsLicenseSettings{
   193  			Seats:            Ptr(0),
   194  			Evaluation:       Ptr(false),
   195  			Perpetual:        Ptr(false),
   196  			UnlimitedSeating: Ptr(true),
   197  			SupportKey:       Ptr("ssh-rsa AAAAB3N...."),
   198  			SSHAllowed:       Ptr(true),
   199  			ClusterSupport:   Ptr(false),
   200  			ExpireAt:         &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)},
   201  		},
   202  		GithubSSL: &ConfigSettingsGithubSSL{
   203  			Enabled: Ptr(false),
   204  			Cert:    nil,
   205  			Key:     nil,
   206  		},
   207  		LDAP: &ConfigSettingsLDAP{
   208  			Host:                    nil,
   209  			Port:                    Ptr(0),
   210  			Base:                    []string{},
   211  			UID:                     nil,
   212  			BindDN:                  nil,
   213  			Password:                nil,
   214  			Method:                  Ptr("Plain"),
   215  			SearchStrategy:          Ptr("detect"),
   216  			UserGroups:              []string{},
   217  			AdminGroup:              nil,
   218  			VirtualAttributeEnabled: Ptr(false),
   219  			RecursiveGroupSearch:    Ptr(false),
   220  			PosixSupport:            Ptr(true),
   221  			UserSyncEmails:          Ptr(false),
   222  			UserSyncKeys:            Ptr(false),
   223  			UserSyncInterval:        Ptr(4),
   224  			TeamSyncInterval:        Ptr(4),
   225  			SyncEnabled:             Ptr(false),
   226  			Reconciliation: &ConfigSettingsLDAPReconciliation{
   227  				User: nil,
   228  				Org:  nil,
   229  			},
   230  			Profile: &ConfigSettingsLDAPProfile{
   231  				UID:  Ptr("uid"),
   232  				Name: nil,
   233  				Mail: nil,
   234  				Key:  nil,
   235  			},
   236  		},
   237  		CAS: &ConfigSettingsCAS{
   238  			URL: nil,
   239  		},
   240  		SAML: &ConfigSettingsSAML{
   241  			SSOURL:             nil,
   242  			Certificate:        nil,
   243  			CertificatePath:    nil,
   244  			Issuer:             nil,
   245  			IDPInitiatedSSO:    Ptr(false),
   246  			DisableAdminDemote: Ptr(false),
   247  		},
   248  		GithubOAuth: &ConfigSettingsGithubOAuth{
   249  			ClientID:         Ptr("12313412"),
   250  			ClientSecret:     Ptr("kj123131132"),
   251  			OrganizationName: Ptr("Homestar Runners"),
   252  			OrganizationTeam: Ptr("homestarrunners/characters"),
   253  		},
   254  		SMTP: &ConfigSettingsSMTP{
   255  			Enabled:                 Ptr(true),
   256  			Address:                 Ptr("smtp.example.com"),
   257  			Authentication:          Ptr("plain"),
   258  			Port:                    Ptr("1234"),
   259  			Domain:                  Ptr("blah"),
   260  			Username:                Ptr("foo"),
   261  			UserName:                Ptr("mr_foo"),
   262  			Password:                Ptr("bar"),
   263  			DiscardToNoreplyAddress: Ptr(true),
   264  			SupportAddress:          Ptr("enterprise@github.com"),
   265  			SupportAddressType:      Ptr("email"),
   266  			NoreplyAddress:          Ptr("noreply@github.com"),
   267  			EnableStarttlsAuto:      Ptr(true),
   268  		},
   269  		NTP: &ConfigSettingsNTP{
   270  			PrimaryServer:   Ptr("0.pool.ntp.org"),
   271  			SecondaryServer: Ptr("1.pool.ntp.org"),
   272  		},
   273  		Timezone: nil,
   274  		SNMP: &ConfigSettingsSNMP{
   275  			Enabled:   Ptr(false),
   276  			Community: Ptr(""),
   277  		},
   278  		Syslog: &ConfigSettingsSyslog{
   279  			Enabled:      Ptr(false),
   280  			Server:       nil,
   281  			ProtocolName: Ptr("udp"),
   282  		},
   283  		Assets: nil,
   284  		Pages: &ConfigSettingsPagesSettings{
   285  			Enabled: Ptr(true),
   286  		},
   287  		Collectd: &ConfigSettingsCollectd{
   288  			Enabled:    Ptr(false),
   289  			Server:     nil,
   290  			Port:       Ptr(0),
   291  			Encryption: nil,
   292  			Username:   nil,
   293  			Password:   nil,
   294  		},
   295  		Mapping: &ConfigSettingsMapping{
   296  			Enabled:    Ptr(true),
   297  			Tileserver: nil,
   298  			Basemap:    Ptr("company.map-qsz2zrvs"),
   299  			Token:      nil,
   300  		},
   301  		LoadBalancer: nil,
   302  	}
   303  	if diff := cmp.Diff(want, configSettings); diff != "" {
   304  		t.Errorf("diff mismatch (-want +got):\n%v", diff)
   305  	}
   306  
   307  	const methodName = "Settings"
   308  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   309  		got, resp, err := client.Enterprise.Settings(ctx)
   310  		if got != nil {
   311  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   312  		}
   313  		return resp, err
   314  	})
   315  }
   316  
   317  func TestEnterpriseService_NodeMetadata(t *testing.T) {
   318  	t.Parallel()
   319  	client, mux, _ := setup(t)
   320  
   321  	mux.HandleFunc("/manage/v1/config/nodes", func(w http.ResponseWriter, r *http.Request) {
   322  		testMethod(t, r, "GET")
   323  		testFormValues(t, r, values{
   324  			"uuid":          "1234-1234",
   325  			"cluster_roles": "primary",
   326  		})
   327  		fmt.Fprint(w, `{
   328  			"topology": "Cluster",
   329  			"nodes": [{
   330  				"hostname": "data1",
   331  				"uuid": "1b6cf518-f97c-11ed-8544-061d81f7eedb",
   332  				"cluster_roles": [
   333  					"ConsulServer"
   334  				]
   335  			}]
   336  		}`)
   337  	})
   338  
   339  	opt := &NodeQueryOptions{
   340  		UUID: Ptr("1234-1234"), ClusterRoles: Ptr("primary"),
   341  	}
   342  	ctx := context.Background()
   343  	configNodes, _, err := client.Enterprise.NodeMetadata(ctx, opt)
   344  	if err != nil {
   345  		t.Errorf("Enterprise.NodeMetadata returned error: %v", err)
   346  	}
   347  
   348  	want := &NodeMetadataStatus{
   349  		Topology: Ptr("Cluster"),
   350  		Nodes: []*NodeDetails{{
   351  			Hostname: Ptr("data1"),
   352  			UUID:     Ptr("1b6cf518-f97c-11ed-8544-061d81f7eedb"),
   353  			ClusterRoles: []string{
   354  				"ConsulServer",
   355  			},
   356  		}},
   357  	}
   358  	if !cmp.Equal(configNodes, want) {
   359  		t.Errorf("Enterprise.NodeMetadata returned %+v, want %+v", configNodes, want)
   360  	}
   361  
   362  	const methodName = "NodeMetadata"
   363  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   364  		got, resp, err := client.Enterprise.NodeMetadata(ctx, opt)
   365  		if got != nil {
   366  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   367  		}
   368  		return resp, err
   369  	})
   370  }
   371  
   372  func TestEnterpriseService_LicenseStatus(t *testing.T) {
   373  	t.Parallel()
   374  	client, mux, _ := setup(t)
   375  
   376  	mux.HandleFunc("/manage/v1/config/license/check", func(w http.ResponseWriter, r *http.Request) {
   377  		testMethod(t, r, "GET")
   378  		fmt.Fprint(w, `[{
   379  			"status": "valid"
   380  			}]`)
   381  	})
   382  
   383  	ctx := context.Background()
   384  	licenseCheck, _, err := client.Enterprise.LicenseStatus(ctx)
   385  	if err != nil {
   386  		t.Errorf("Enterprise.LicenseStatus returned error: %v", err)
   387  	}
   388  
   389  	want := []*LicenseCheck{{
   390  		Status: Ptr("valid"),
   391  	}}
   392  	if !cmp.Equal(licenseCheck, want) {
   393  		t.Errorf("Enterprise.LicenseStatus returned %+v, want %+v", licenseCheck, want)
   394  	}
   395  
   396  	const methodName = "LicenseStatus"
   397  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   398  		got, resp, err := client.Enterprise.LicenseStatus(ctx)
   399  		if got != nil {
   400  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   401  		}
   402  		return resp, err
   403  	})
   404  }
   405  
   406  func TestEnterpriseService_License(t *testing.T) {
   407  	t.Parallel()
   408  	client, mux, _ := setup(t)
   409  
   410  	mux.HandleFunc("/manage/v1/config/license", func(w http.ResponseWriter, r *http.Request) {
   411  		testMethod(t, r, "GET")
   412  		fmt.Fprint(w, `[{
   413  			"advancedSecurityEnabled": true,
   414  			"advancedSecuritySeats": 0,
   415  			"clusterSupport": false,
   416  			"company": "GitHub",
   417  			"croquetSupport": true,
   418  			"customTerms": true,
   419  			"evaluation": false,
   420  			"expireAt": "2018-01-01T00:00:00Z",
   421  			"insightsEnabled": true,
   422  			"insightsExpireAt": "2018-01-01T00:00:00Z",
   423  			"learningLabEvaluationExpires": "2018-01-01T00:00:00Z",
   424  			"learningLabSeats": 100,
   425  			"perpetual": false,
   426  			"referenceNumber": "32a145",
   427  			"seats": 0,
   428  			"sshAllowed": true,
   429  			"supportKey": "",
   430  			"unlimitedSeating": true
   431  		}]`)
   432  	})
   433  
   434  	ctx := context.Background()
   435  	license, _, err := client.Enterprise.License(ctx)
   436  	if err != nil {
   437  		t.Errorf("Enterprise.License returned error: %v", err)
   438  	}
   439  
   440  	want := []*LicenseStatus{{
   441  		AdvancedSecurityEnabled:      Ptr(true),
   442  		AdvancedSecuritySeats:        Ptr(0),
   443  		ClusterSupport:               Ptr(false),
   444  		Company:                      Ptr("GitHub"),
   445  		CroquetSupport:               Ptr(true),
   446  		CustomTerms:                  Ptr(true),
   447  		Evaluation:                   Ptr(false),
   448  		ExpireAt:                     &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)},
   449  		InsightsEnabled:              Ptr(true),
   450  		InsightsExpireAt:             &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)},
   451  		LearningLabEvaluationExpires: &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)},
   452  		LearningLabSeats:             Ptr(100),
   453  		Perpetual:                    Ptr(false),
   454  		ReferenceNumber:              Ptr("32a145"),
   455  		Seats:                        Ptr(0),
   456  		SSHAllowed:                   Ptr(true),
   457  		SupportKey:                   Ptr(""),
   458  		UnlimitedSeating:             Ptr(true),
   459  	}}
   460  	if diff := cmp.Diff(want, license); diff != "" {
   461  		t.Errorf("diff mismatch (-want +got):\n%v", diff)
   462  	}
   463  	const methodName = "License"
   464  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   465  		got, resp, err := client.Enterprise.License(ctx)
   466  		if got != nil {
   467  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   468  		}
   469  		return resp, err
   470  	})
   471  }
   472  
   473  func TestEnterpriseService_ConfigApplyEvents(t *testing.T) {
   474  	t.Parallel()
   475  	client, mux, _ := setup(t)
   476  
   477  	mux.HandleFunc("/manage/v1/config/apply/events", func(w http.ResponseWriter, r *http.Request) {
   478  		testMethod(t, r, "GET")
   479  		fmt.Fprint(w, `{
   480  			"nodes": [{
   481  				"node": "ghes-01.lan",
   482  				"last_request_id": "387cd628c06d606700e79be368e5e574:0cde553750689c76:0000000000000000",
   483  				"events": [{
   484  					"timestamp": "2018-01-01T00:00:00+00:00",
   485  					"severity_text": "INFO",
   486  					"body": "Validating services",
   487  					"event_name": "Enterprise::ConfigApply::PhaseValidation#config_phase_validation",
   488  					"topology": "multinode",
   489  					"hostname": "ghes-01.lan",
   490  					"config_run_id": "d34db33f",
   491  					"trace_id": "387cd628c06d606700e79be368e5e574",
   492  					"span_id": "0cde553750689c76",
   493  					"span_parent_id": 0,
   494  					"span_depth": 0
   495  					}]
   496  				}]
   497  			}`)
   498  	})
   499  
   500  	input := &ConfigApplyEventsOptions{
   501  		LastRequestID: Ptr("387cd628c06d606700e79be368e5e574:0cde553750689"),
   502  	}
   503  
   504  	ctx := context.Background()
   505  	configEvents, _, err := client.Enterprise.ConfigApplyEvents(ctx, input)
   506  	if err != nil {
   507  		t.Errorf("Enterprise.ConfigApplyEvents returned error: %v", err)
   508  	}
   509  
   510  	want := &ConfigApplyEvents{
   511  		Nodes: []*ConfigApplyEventsNode{{
   512  			Node:          Ptr("ghes-01.lan"),
   513  			LastRequestID: Ptr("387cd628c06d606700e79be368e5e574:0cde553750689c76:0000000000000000"),
   514  			Events: []*ConfigApplyEventsNodeEvent{{
   515  				Timestamp:    &Timestamp{time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)},
   516  				SeverityText: Ptr("INFO"),
   517  				Body:         Ptr("Validating services"),
   518  				EventName:    Ptr("Enterprise::ConfigApply::PhaseValidation#config_phase_validation"),
   519  				Topology:     Ptr("multinode"),
   520  				Hostname:     Ptr("ghes-01.lan"),
   521  				ConfigRunID:  Ptr("d34db33f"),
   522  				TraceID:      Ptr("387cd628c06d606700e79be368e5e574"),
   523  				SpanID:       Ptr("0cde553750689c76"),
   524  				SpanParentID: Ptr(int64(0)),
   525  				SpanDepth:    Ptr(0),
   526  			}},
   527  		}},
   528  	}
   529  	if diff := cmp.Diff(want, configEvents); diff != "" {
   530  		t.Errorf("diff mismatch (-want +got):\n%v", diff)
   531  	}
   532  	if !cmp.Equal(configEvents, want) {
   533  		t.Errorf("Enterprise.ConfigApplyEvents returned %+v, want %+v", configEvents, want)
   534  	}
   535  
   536  	const methodName = "ConfigApplyEvents"
   537  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   538  		got, resp, err := client.Enterprise.ConfigApplyEvents(ctx, input)
   539  		if got != nil {
   540  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   541  		}
   542  		return resp, err
   543  	})
   544  }
   545  
   546  func TestEnterpriseService_UpdateSettings(t *testing.T) {
   547  	t.Parallel()
   548  	client, mux, _ := setup(t)
   549  
   550  	mux.HandleFunc("/manage/v1/config/settings", func(w http.ResponseWriter, r *http.Request) {
   551  		testMethod(t, r, "PUT")
   552  
   553  		w.WriteHeader(http.StatusNoContent)
   554  	})
   555  
   556  	input := &ConfigSettings{
   557  		PrivateMode: Ptr(false),
   558  	}
   559  
   560  	ctx := context.Background()
   561  	if _, err := client.Enterprise.UpdateSettings(ctx, input); err != nil {
   562  		t.Errorf("Enterprise.UpdateSettings returned error: %v", err)
   563  	}
   564  
   565  	const methodName = "UpdateSettings"
   566  	testBadOptions(t, methodName, func() (err error) {
   567  		_, err = client.Enterprise.UpdateSettings(ctx, nil)
   568  		return err
   569  	})
   570  
   571  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   572  		return client.Enterprise.UpdateSettings(ctx, input)
   573  	})
   574  }
   575  
   576  func TestEnterpriseService_UploadLicense(t *testing.T) {
   577  	t.Parallel()
   578  	client, mux, _ := setup(t)
   579  
   580  	mux.HandleFunc("/manage/v1/config/license", func(w http.ResponseWriter, r *http.Request) {
   581  		testMethod(t, r, "PUT")
   582  
   583  		w.WriteHeader(http.StatusNoContent)
   584  	})
   585  
   586  	ctx := context.Background()
   587  	if _, err := client.Enterprise.UploadLicense(ctx, "abc"); err != nil {
   588  		t.Errorf("Enterprise.UploadLicense returned error: %v", err)
   589  	}
   590  
   591  	const methodName = "UploadLicense"
   592  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   593  		return client.Enterprise.UploadLicense(ctx, "")
   594  	})
   595  }
   596  
   597  func TestEnterpriseService_InitialConfig(t *testing.T) {
   598  	t.Parallel()
   599  	client, mux, _ := setup(t)
   600  
   601  	input := &InitialConfigOptions{
   602  		License:  "1234-1234",
   603  		Password: "password",
   604  	}
   605  
   606  	mux.HandleFunc("/manage/v1/config/init", func(w http.ResponseWriter, r *http.Request) {
   607  		v := new(InitialConfigOptions)
   608  		assertNilError(t, json.NewDecoder(r.Body).Decode(v))
   609  
   610  		testMethod(t, r, "POST")
   611  		if diff := cmp.Diff(v, input); diff != "" {
   612  			t.Errorf("diff mismatch (-want +got):\n%v", diff)
   613  		}
   614  	})
   615  
   616  	ctx := context.Background()
   617  	if _, err := client.Enterprise.InitialConfig(ctx, "1234-1234", "password"); err != nil {
   618  		t.Errorf("Enterprise.InitialConfig returned error: %v", err)
   619  	}
   620  
   621  	const methodName = "InitialConfig"
   622  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   623  		return client.Enterprise.InitialConfig(ctx, "", "")
   624  	})
   625  }
   626  
   627  func TestEnterpriseService_ConfigApply(t *testing.T) {
   628  	t.Parallel()
   629  	client, mux, _ := setup(t)
   630  
   631  	mux.HandleFunc("/manage/v1/config/apply", func(w http.ResponseWriter, r *http.Request) {
   632  		testMethod(t, r, "POST")
   633  		got := new(ConfigApplyOptions)
   634  		assertNilError(t, json.NewDecoder(r.Body).Decode(got))
   635  
   636  		want := &ConfigApplyOptions{
   637  			RunID: Ptr("1234"),
   638  		}
   639  		if diff := cmp.Diff(want, got); diff != "" {
   640  			t.Errorf("diff mismatch (-want +got):\n%v", diff)
   641  		}
   642  		fmt.Fprint(w, `{ "run_id": "1234" }`)
   643  	})
   644  
   645  	input := &ConfigApplyOptions{
   646  		RunID: Ptr("1234"),
   647  	}
   648  
   649  	ctx := context.Background()
   650  	configApply, _, err := client.Enterprise.ConfigApply(ctx, input)
   651  	if err != nil {
   652  		t.Errorf("Enterprise.ConfigApply returned error: %v", err)
   653  	}
   654  	want := &ConfigApplyOptions{
   655  		RunID: Ptr("1234"),
   656  	}
   657  	if !cmp.Equal(configApply, want) {
   658  		t.Errorf("Enterprise.ConfigApply returned %+v, want %+v", configApply, want)
   659  	}
   660  	const methodName = "ConfigApply"
   661  
   662  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   663  		got, resp, err := client.Enterprise.ConfigApply(ctx, input)
   664  		if got != nil {
   665  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   666  		}
   667  		return resp, err
   668  	})
   669  }
   670  
   671  func TestEnterpriseService_ConfigApplyStatus(t *testing.T) {
   672  	t.Parallel()
   673  	client, mux, _ := setup(t)
   674  
   675  	mux.HandleFunc("/manage/v1/config/apply", func(w http.ResponseWriter, r *http.Request) {
   676  		testMethod(t, r, "GET")
   677  		got := new(ConfigApplyOptions)
   678  		assertNilError(t, json.NewDecoder(r.Body).Decode(got))
   679  
   680  		want := &ConfigApplyOptions{
   681  			RunID: Ptr("1234"),
   682  		}
   683  		if diff := cmp.Diff(want, got); diff != "" {
   684  			t.Errorf("diff mismatch (-want +got):\n%v", diff)
   685  		}
   686  		fmt.Fprint(w, `{
   687  			"running": true,
   688  			"successful": false,
   689  			"nodes": [
   690  				{
   691  				"run_id": "d34db33f",
   692  				"hostname": "ghes-01.lan",
   693  				"running": true,
   694  				"successful": false
   695  				}
   696  			]
   697  		}`)
   698  	})
   699  	input := &ConfigApplyOptions{
   700  		RunID: Ptr("1234"),
   701  	}
   702  	ctx := context.Background()
   703  	configApplyStatus, _, err := client.Enterprise.ConfigApplyStatus(ctx, input)
   704  	if err != nil {
   705  		t.Errorf("Enterprise.ConfigApplyStatus returned error: %v", err)
   706  	}
   707  	want := &ConfigApplyStatus{
   708  		Running:    Ptr(true),
   709  		Successful: Ptr(false),
   710  		Nodes: []*ConfigApplyStatusNode{{
   711  			RunID:      Ptr("d34db33f"),
   712  			Hostname:   Ptr("ghes-01.lan"),
   713  			Running:    Ptr(true),
   714  			Successful: Ptr(false),
   715  		}},
   716  	}
   717  	if !cmp.Equal(configApplyStatus, want) {
   718  		t.Errorf("Enterprise.ConfigApplyStatus returned %+v, want %+v", configApplyStatus, want)
   719  	}
   720  	const methodName = "ConfigApplyStatus"
   721  
   722  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   723  		got, resp, err := client.Enterprise.ConfigApplyStatus(ctx, input)
   724  		if got != nil {
   725  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   726  		}
   727  		return resp, err
   728  	})
   729  }