コード例 #1
0
ファイル: application_bits.go プロジェクト: knolleary/cli
func (repo CloudControllerApplicationBitsRepository) uploadBits(appGuid string, zipFile *os.File, presentResourcesJson []byte) (apiErr errors.Error) {
	url := fmt.Sprintf("%s/v2/apps/%s/bits", repo.config.ApiEndpoint(), appGuid)
	fileutils.TempFile("requests", func(requestFile *os.File, err error) {
		if err != nil {
			apiErr = errors.NewErrorWithError("Error creating tmp file: %s", err)
			return
		}

		boundary, err := repo.writeUploadBody(zipFile, requestFile, presentResourcesJson)
		if err != nil {
			apiErr = errors.NewErrorWithError("Error writing to tmp file: %s", err)
			return
		}

		var request *net.Request
		request, apiErr = repo.gateway.NewRequest("PUT", url, repo.config.AccessToken(), requestFile)
		if apiErr != nil {
			return
		}

		contentType := fmt.Sprintf("multipart/form-data; boundary=%s", boundary)
		request.HttpReq.Header.Set("Content-Type", contentType)

		response := &Resource{}
		_, apiErr = repo.gateway.PerformPollingRequestForJSONResponse(request, response, 5*time.Minute)
		if apiErr != nil {
			return
		}
	})

	return
}
コード例 #2
0
ファイル: buildpack_bits.go プロジェクト: jibin-tomy/cli
func (repo CloudControllerBuildpackBitsRepository) UploadBuildpack(buildpack models.Buildpack, buildpackLocation string) (apiErr errors.Error) {
	fileutils.TempFile("buildpack-upload", func(zipFileToUpload *os.File, err error) {
		if err != nil {
			apiErr = errors.NewErrorWithError("Couldn't create temp file for upload", err)
			return
		}

		var buildpackFileName string
		if isWebURL(buildpackLocation) {
			buildpackFileName = path.Base(buildpackLocation)
			repo.downloadBuildpack(buildpackLocation, func(downloadFile *os.File, downloadErr error) {
				if downloadErr != nil {
					err = downloadErr
					return
				}

				err = normalizeBuildpackArchive(downloadFile, zipFileToUpload)
			})
		} else {
			buildpackFileName = filepath.Base(buildpackLocation)

			stats, err := os.Stat(buildpackLocation)
			if err != nil {
				apiErr = errors.NewErrorWithError("Error opening buildpack file", err)
				return
			}

			if stats.IsDir() {
				err = repo.zipper.Zip(buildpackLocation, zipFileToUpload)
			} else {
				specifiedFile, err := os.Open(buildpackLocation)
				if err != nil {
					apiErr = errors.NewErrorWithError("Couldn't open buildpack file", err)
					return
				}
				err = normalizeBuildpackArchive(specifiedFile, zipFileToUpload)
			}
		}

		if err != nil {
			apiErr = errors.NewErrorWithError("Couldn't write zip file", err)
			return
		}

		apiErr = repo.uploadBits(buildpack, zipFileToUpload, buildpackFileName)
	})

	return
}
コード例 #3
0
ファイル: application_bits.go プロジェクト: knolleary/cli
func (repo CloudControllerApplicationBitsRepository) UploadApp(appGuid string, appDir string, cb func(path string, zipSize, fileCount uint64)) (apiErr errors.Error) {
	fileutils.TempDir("apps", func(uploadDir string, err error) {
		if err != nil {
			apiErr = errors.NewErrorWithMessage(err.Error())
			return
		}

		var presentResourcesJson []byte
		repo.sourceDir(appDir, func(sourceDir string, sourceErr error) {
			if sourceErr != nil {
				err = sourceErr
				return
			}
			presentResourcesJson, err = repo.copyUploadableFiles(sourceDir, uploadDir)
		})

		if err != nil {
			apiErr = errors.NewErrorWithMessage("%s", err)
			return
		}

		fileutils.TempFile("uploads", func(zipFile *os.File, err error) {
			if err != nil {
				apiErr = errors.NewErrorWithMessage("%s", err.Error())
				return
			}

			err = repo.zipper.Zip(uploadDir, zipFile)
			if err != nil {
				apiErr = errors.NewErrorWithError("Error zipping application", err)
				return
			}

			stat, err := zipFile.Stat()
			if err != nil {
				apiErr = errors.NewErrorWithError("Error zipping application", err)
				return
			}
			cb(appDir, uint64(stat.Size()), app_files.CountFiles(uploadDir))

			apiErr = repo.uploadBits(appGuid, zipFile, presentResourcesJson)
			if apiErr != nil {
				return
			}
		})
	})
	return
}
コード例 #4
0
ファイル: gateway.go プロジェクト: knolleary/cli
func (gateway Gateway) ListPaginatedResources(target string,
	accessToken string,
	path string,
	resource interface{},
	cb func(interface{}) bool) (apiErr errors.Error) {

	for path != "" {
		pagination := NewPaginatedResources(resource)
		apiErr = gateway.GetResource(fmt.Sprintf("%s%s", target, path), accessToken, &pagination)
		if apiErr != nil {
			return
		}

		resources, err := pagination.Resources()
		if err != nil {
			return errors.NewErrorWithError("Error parsing JSON", err)
		}

		for _, resource := range resources {
			if !cb(resource) {
				return
			}
		}

		path = pagination.NextURL
	}

	return
}
コード例 #5
0
ファイル: gateway.go プロジェクト: knolleary/cli
func (gateway Gateway) NewRequest(method, path, accessToken string, body io.ReadSeeker) (req *Request, apiErr errors.Error) {
	if body != nil {
		body.Seek(0, 0)
	}

	request, err := http.NewRequest(method, path, body)
	if err != nil {
		apiErr = errors.NewErrorWithError("Error building request", err)
		return
	}

	if accessToken != "" {
		request.Header.Set("Authorization", accessToken)
	}

	request.Header.Set("accept", "application/json")
	request.Header.Set("content-type", "application/json")
	request.Header.Set("User-Agent", "go-cli "+cf.Version+" / "+runtime.GOOS)

	if body != nil {
		switch v := body.(type) {
		case *os.File:
			fileStats, err := v.Stat()
			if err != nil {
				break
			}
			request.ContentLength = fileStats.Size()
		}
	}

	req = &Request{HttpReq: request, SeekableBody: body}
	return
}
コード例 #6
0
ファイル: application_bits.go プロジェクト: knolleary/cli
func (repo CloudControllerApplicationBitsRepository) getFilesToUpload(allAppFiles []models.AppFileFields) (appFilesToUpload []models.AppFileFields, presentResourcesJson []byte, apiErr errors.Error) {
	appFilesRequest := []AppFileResource{}
	for _, file := range allAppFiles {
		appFilesRequest = append(appFilesRequest, AppFileResource{
			Path: file.Path,
			Sha1: file.Sha1,
			Size: file.Size,
		})
	}

	allAppFilesJson, err := json.Marshal(appFilesRequest)
	if err != nil {
		apiErr = errors.NewErrorWithError("Failed to create json for resource_match request", err)
		return
	}

	path := fmt.Sprintf("%s/v2/resource_match", repo.config.ApiEndpoint())
	req, apiErr := repo.gateway.NewRequest("PUT", path, repo.config.AccessToken(), bytes.NewReader(allAppFilesJson))
	if apiErr != nil {
		return
	}

	presentResourcesJson, _, _, apiErr = repo.gateway.PerformRequestForResponseBytes(req)

	fileResource := []AppFileResource{}
	err = json.Unmarshal(presentResourcesJson, &fileResource)

	if err != nil {
		apiErr = errors.NewErrorWithError("Failed to unmarshal json response from resource_match request", err)
		return
	}

	appFilesToUpload = make([]models.AppFileFields, len(allAppFiles))
	copy(appFilesToUpload, allAppFiles)
	for _, file := range fileResource {
		appFile := models.AppFileFields{
			Path: file.Path,
			Sha1: file.Sha1,
			Size: file.Size,
		}
		appFilesToUpload = repo.deleteAppFile(appFilesToUpload, appFile)
	}

	return
}
コード例 #7
0
ファイル: gateway.go プロジェクト: knolleary/cli
func (gateway Gateway) PerformPollingRequestForJSONResponse(request *Request, response interface{}, timeout time.Duration) (headers http.Header, apiErr errors.Error) {
	query := request.HttpReq.URL.Query()
	query.Add("async", "true")
	request.HttpReq.URL.RawQuery = query.Encode()

	bytes, headers, rawResponse, apiErr := gateway.PerformRequestForResponseBytes(request)
	if apiErr != nil {
		return
	}

	if rawResponse.StatusCode > 203 || strings.TrimSpace(string(bytes)) == "" {
		return
	}

	err := json.Unmarshal(bytes, &response)
	if err != nil {
		apiErr = errors.NewErrorWithError("Invalid JSON response from server", err)
		return
	}

	asyncResponse := &AsyncResponse{}

	err = json.Unmarshal(bytes, &asyncResponse)
	if err != nil {
		apiErr = errors.NewErrorWithError("Invalid async response from server", err)
		return
	}

	jobUrl := asyncResponse.Metadata.Url
	if jobUrl == "" {
		return
	}

	if !strings.Contains(jobUrl, "/jobs/") {
		return
	}

	jobUrl = fmt.Sprintf("%s://%s%s", request.HttpReq.URL.Scheme, request.HttpReq.URL.Host, asyncResponse.Metadata.Url)
	apiErr = gateway.waitForJob(jobUrl, request.HttpReq.Header.Get("Authorization"), timeout)

	return
}
コード例 #8
0
ファイル: ssl.go プロジェクト: knolleary/cli
func wrapSSLErrorInternal(host string, err error) errors.Error {
	switch err.(type) {
	case x509.UnknownAuthorityError:
		return errors.NewInvalidSSLCert(host, "unknown authority")
	case x509.HostnameError:
		return errors.NewInvalidSSLCert(host, "not valid for the requested host")
	case x509.CertificateInvalidError:
		return errors.NewInvalidSSLCert(host, "")
	default:
		return errors.NewErrorWithError("Error performing request", err)
	}
}
コード例 #9
0
ファイル: authentication.go プロジェクト: knolleary/cli
func (uaa UAAAuthenticationRepository) getAuthToken(data url.Values) errors.Error {
	type uaaErrorResponse struct {
		Code        string `json:"error"`
		Description string `json:"error_description"`
	}

	type AuthenticationResponse struct {
		AccessToken  string           `json:"access_token"`
		TokenType    string           `json:"token_type"`
		RefreshToken string           `json:"refresh_token"`
		Error        uaaErrorResponse `json:"error"`
	}

	path := fmt.Sprintf("%s/oauth/token", uaa.config.AuthenticationEndpoint())
	request, err := uaa.gateway.NewRequest("POST", path, "Basic "+base64.StdEncoding.EncodeToString([]byte("cf:")), strings.NewReader(data.Encode()))
	if err != nil {
		return errors.NewErrorWithError("Failed to start oauth request", err)
	}
	request.HttpReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	response := new(AuthenticationResponse)
	_, err = uaa.gateway.PerformRequestForJSONResponse(request, &response)

	switch err.(type) {
	case nil:
	case errors.HttpError:
		return err
	default:
		return errors.NewErrorWithError("auth request failed", err)
	}

	if response.Error.Code != "" {
		return errors.NewError("Authentication Server error: "+response.Error.Description, response.Error.Code)
	}

	uaa.config.SetAccessToken(fmt.Sprintf("%s %s", response.TokenType, response.AccessToken))
	uaa.config.SetRefreshToken(response.RefreshToken)

	return nil
}
コード例 #10
0
ファイル: ssl.go プロジェクト: knolleary/cli
func WrapSSLErrors(host string, err error) errors.Error {
	urlError, ok := err.(*url.Error)
	if ok {
		return wrapSSLErrorInternal(host, urlError.Err)
	}

	websocketError, ok := err.(*websocket.DialError)
	if ok {
		return wrapSSLErrorInternal(host, websocketError.Err)
	}

	return errors.NewErrorWithError("Error performing request", err)
}
コード例 #11
0
ファイル: gateway.go プロジェクト: knolleary/cli
func (gateway Gateway) PerformRequestForResponseBytes(request *Request) (bytes []byte, headers http.Header, rawResponse *http.Response, apiErr errors.Error) {
	rawResponse, apiErr = gateway.doRequestHandlingAuth(request)
	if apiErr != nil {
		return
	}

	bytes, err := ioutil.ReadAll(rawResponse.Body)
	if err != nil {
		apiErr = errors.NewErrorWithError("Error reading response", err)
	}

	headers = rawResponse.Header
	return
}
コード例 #12
0
ファイル: ssl.go プロジェクト: jibin-tomy/cli
func wrapSSLErrors(host string, err error) errors.Error {
	urlError, ok := err.(*url.Error)
	if ok {
		switch urlError.Err.(type) {
		case x509.UnknownAuthorityError:
			return errors.NewInvalidSSLCert(host, "unknown authority")
		case x509.HostnameError:
			return errors.NewInvalidSSLCert(host, "not valid for the requested host")
		case x509.CertificateInvalidError:
			return errors.NewInvalidSSLCert(host, "")
		}
	}
	return errors.NewErrorWithError("Error performing request", err)
}
コード例 #13
0
ファイル: curl.go プロジェクト: knolleary/cli
func (repo CloudControllerCurlRepository) Request(method, path, headerString, body string) (resHeaders, resBody string, apiErr errors.Error) {
	url := fmt.Sprintf("%s/%s", repo.config.ApiEndpoint(), strings.TrimLeft(path, "/"))

	req, apiErr := repo.gateway.NewRequest(method, url, repo.config.AccessToken(), strings.NewReader(body))
	if apiErr != nil {
		return
	}

	err := mergeHeaders(req.HttpReq.Header, headerString)
	if err != nil {
		apiErr = errors.NewErrorWithError("Error parsing headers", err)
		return
	}

	res, apiErr := repo.gateway.PerformRequestForResponse(req)

	if apiErr != nil {
		if httpErr, ok := apiErr.(errors.HttpError); ok {
			resHeaders = httpErr.Headers()
			resBody = httpErr.Body()
			apiErr = nil
		}

		return
	}

	headerBytes, _ := httputil.DumpResponse(res, false)
	resHeaders = string(headerBytes)

	bytes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		apiErr = errors.NewErrorWithError("Error reading response", err)
	}
	resBody = string(bytes)

	return
}
コード例 #14
0
ファイル: gateway.go プロジェクト: knolleary/cli
func (gateway Gateway) PerformRequestForJSONResponse(request *Request, response interface{}) (headers http.Header, apiErr errors.Error) {
	bytes, headers, rawResponse, apiErr := gateway.PerformRequestForResponseBytes(request)
	if apiErr != nil {
		return
	}

	if rawResponse.StatusCode > 203 || strings.TrimSpace(string(bytes)) == "" {
		return
	}

	err := json.Unmarshal(bytes, &response)
	if err != nil {
		apiErr = errors.NewErrorWithError("Invalid JSON response from server", err)
	}
	return
}
コード例 #15
0
ファイル: applications.go プロジェクト: knolleary/cli
func (repo CloudControllerApplicationRepository) Update(appGuid string, params models.AppParams) (updatedApp models.Application, apiErr errors.Error) {
	data, err := repo.formatAppJSON(params)
	if err != nil {
		apiErr = errors.NewErrorWithError("Failed to marshal JSON", err)
		return
	}

	path := fmt.Sprintf("%s/v2/apps/%s?inline-relations-depth=1", repo.config.ApiEndpoint(), appGuid)
	resource := new(ApplicationResource)
	apiErr = repo.gateway.UpdateResourceForResponse(path, repo.config.AccessToken(), strings.NewReader(data), resource)
	if apiErr != nil {
		return
	}

	updatedApp = resource.ToModel()
	return
}
コード例 #16
0
func (repo CCUserProvidedServiceInstanceRepository) Update(serviceInstanceFields models.ServiceInstanceFields) (apiErr errors.Error) {
	path := fmt.Sprintf("%s/v2/user_provided_service_instances/%s", repo.config.ApiEndpoint(), serviceInstanceFields.Guid)

	type RequestBody struct {
		Credentials    map[string]string `json:"credentials,omitempty"`
		SysLogDrainUrl string            `json:"syslog_drain_url,omitempty"`
	}

	reqBody := RequestBody{serviceInstanceFields.Params, serviceInstanceFields.SysLogDrainUrl}
	jsonBytes, err := json.Marshal(reqBody)
	if err != nil {
		apiErr = errors.NewErrorWithError("Error parsing response", err)
		return
	}

	return repo.gateway.UpdateResource(path, repo.config.AccessToken(), bytes.NewReader(jsonBytes))
}
コード例 #17
0
ファイル: buildpacks.go プロジェクト: knolleary/cli
func (repo CloudControllerBuildpackRepository) Create(name string, position *int, enabled *bool, locked *bool) (createdBuildpack models.Buildpack, apiErr errors.Error) {
	path := repo.config.ApiEndpoint() + buildpacks_path
	entity := BuildpackEntity{Name: name, Position: position, Enabled: enabled, Locked: locked}
	body, err := json.Marshal(entity)
	if err != nil {
		apiErr = errors.NewErrorWithError("Could not serialize information", err)
		return
	}

	resource := new(BuildpackResource)
	apiErr = repo.gateway.CreateResourceForResponse(path, repo.config.AccessToken(), bytes.NewReader(body), resource)
	if apiErr != nil {
		return
	}

	createdBuildpack = resource.ToFields()
	return
}
コード例 #18
0
ファイル: buildpacks.go プロジェクト: knolleary/cli
func (repo CloudControllerBuildpackRepository) Update(buildpack models.Buildpack) (updatedBuildpack models.Buildpack, apiErr errors.Error) {
	path := fmt.Sprintf("%s%s/%s", repo.config.ApiEndpoint(), buildpacks_path, buildpack.Guid)

	entity := BuildpackEntity{buildpack.Name, buildpack.Position, buildpack.Enabled, "", "", buildpack.Locked}

	body, err := json.Marshal(entity)
	if err != nil {
		apiErr = errors.NewErrorWithError("Could not serialize updates.", err)
		return
	}

	resource := new(BuildpackResource)
	apiErr = repo.gateway.UpdateResourceForResponse(path, repo.config.AccessToken(), bytes.NewReader(body), resource)
	if apiErr != nil {
		return
	}

	updatedBuildpack = resource.ToFields()
	return
}
コード例 #19
0
ファイル: buildpack_bits.go プロジェクト: jibin-tomy/cli
func (repo CloudControllerBuildpackBitsRepository) performMultiPartUpload(url string, fieldName string, fileName string, body io.Reader) (apiErr errors.Error) {
	fileutils.TempFile("requests", func(requestFile *os.File, err error) {
		if err != nil {
			apiErr = errors.NewErrorWithMessage(err.Error())
			return
		}

		writer := multipart.NewWriter(requestFile)
		part, err := writer.CreateFormFile(fieldName, fileName)

		if err != nil {
			writer.Close()
			return
		}

		_, err = io.Copy(part, body)
		writer.Close()

		if err != nil {
			apiErr = errors.NewErrorWithError("Error creating upload", err)
			return
		}

		var request *net.Request
		request, apiErr = repo.gateway.NewRequest("PUT", url, repo.config.AccessToken(), requestFile)
		contentType := fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary())
		request.HttpReq.Header.Set("Content-Type", contentType)
		if apiErr != nil {
			return
		}

		apiErr = repo.gateway.PerformRequest(request)
	})

	return
}
コード例 #20
0
func (repo CCUserProvidedServiceInstanceRepository) Create(name, drainUrl string, params map[string]string) (apiErr errors.Error) {
	path := fmt.Sprintf("%s/v2/user_provided_service_instances", repo.config.ApiEndpoint())

	type RequestBody struct {
		Name           string            `json:"name"`
		Credentials    map[string]string `json:"credentials"`
		SpaceGuid      string            `json:"space_guid"`
		SysLogDrainUrl string            `json:"syslog_drain_url"`
	}

	jsonBytes, err := json.Marshal(RequestBody{
		Name:           name,
		Credentials:    params,
		SpaceGuid:      repo.config.SpaceFields().Guid,
		SysLogDrainUrl: drainUrl,
	})

	if err != nil {
		apiErr = errors.NewErrorWithError("Error parsing response", err)
		return
	}

	return repo.gateway.CreateResource(path, repo.config.AccessToken(), bytes.NewReader(jsonBytes))
}
コード例 #21
0
		deps.serviceRepo.FindServiceOfferingByLabelAndProviderServiceOffering = offering

		testcmd.RunCommand(
			NewPurgeServiceOffering(deps.ui, deps.config, deps.serviceRepo),
			testcmd.NewContext("purge-service-offering", []string{"-f", "the-service-name"}),
			deps.reqFactory,
		)

		Expect(len(deps.ui.Prompts)).To(Equal(0))
		Expect(deps.serviceRepo.PurgeServiceOfferingCalled).To(Equal(true))
	})

	It("fails with an error message when the request fails", func() {
		deps := setupDependencies()

		deps.serviceRepo.FindServiceOfferingByLabelAndProviderApiResponse = cferrors.NewErrorWithError("oh no!", errors.New("!"))

		testcmd.RunCommand(
			NewPurgeServiceOffering(deps.ui, deps.config, deps.serviceRepo),
			testcmd.NewContext("purge-service-offering", []string{"-f", "-p", "the-provider", "the-service-name"}),
			deps.reqFactory,
		)

		testassert.SliceContains(deps.ui.Outputs, testassert.Lines{
			{"FAILED"},
			{"oh no!"},
		})

		Expect(deps.serviceRepo.PurgeServiceOfferingCalled).To(Equal(false))
	})
コード例 #22
0
ファイル: domain_test.go プロジェクト: knolleary/cli
	It("succeeds when the domain is found", func() {
		domain := models.DomainFields{Name: "example.com", Guid: "domain-guid"}
		domainRepo := &testapi.FakeDomainRepository{FindByNameInOrgDomain: domain}
		domainReq := NewDomainRequirement("example.com", ui, config, domainRepo)
		success := domainReq.Execute()

		Expect(success).To(BeTrue())
		Expect(domainRepo.FindByNameInOrgName).To(Equal("example.com"))
		Expect(domainRepo.FindByNameInOrgGuid).To(Equal("the-org-guid"))
		Expect(domainReq.GetDomain()).To(Equal(domain))
	})

	It("fails when the domain is not found", func() {
		domainRepo := &testapi.FakeDomainRepository{FindByNameInOrgApiResponse: errors.NewModelNotFoundError("Domain", "")}
		domainReq := NewDomainRequirement("example.com", ui, config, domainRepo)

		testassert.AssertPanic(testterm.FailedWasCalled, func() {
			domainReq.Execute()
		})
	})

	It("fails when an error occurs fetching the domain", func() {
		domainRepo := &testapi.FakeDomainRepository{FindByNameInOrgApiResponse: errors.NewErrorWithError("", errors.New(""))}
		domainReq := NewDomainRequirement("example.com", ui, config, domainRepo)

		testassert.AssertPanic(testterm.FailedWasCalled, func() {
			domainReq.Execute()
		})
	})
})
コード例 #23
0
ファイル: users_test.go プロジェクト: jibin-tomy/cli
			Expect(ok).To(BeTrue())
			Expect(httpErr.StatusCode()).To(Equal(http.StatusGatewayTimeout))
		})

		It("returns an error when the UAA endpoint cannot be determined", func() {
			ccReqs, _ := createUsersByRoleEndpoints("/v2/organizations/my-org-guid/managers")

			ts, _ := testnet.NewServer(ccReqs)
			defer ts.Close()
			configRepo := testconfig.NewRepositoryWithDefaults()
			configRepo.SetApiEndpoint(ts.URL)

			ccGateway := net.NewCloudControllerGateway()
			uaaGateway := net.NewUAAGateway()
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.UAAEndpointReturns.Error = errors.NewErrorWithError("Failed to get endpoint!", errors.New("Failed!"))

			repo := NewCloudControllerUserRepository(configRepo, uaaGateway, ccGateway, endpointRepo)

			_, apiErr := repo.ListUsersInOrgForRole("my-org-guid", models.ORG_MANAGER)

			Expect(apiErr).To(Equal(endpointRepo.UAAEndpointReturns.Error))
		})
	})

	It("TestFindByUsername", func() {
		usersResponse := `{ "resources": [{ "id": "my-guid", "userName": "******" }]}`
		uaaReq := testapi.NewCloudControllerTestRequest(testnet.TestRequest{
			Method:   "GET",
			Path:     "/Users?attributes=id,userName&filter=userName+Eq+%22damien%2Buser1%40pivotallabs.com%22",
			Response: testnet.TestResponse{Status: http.StatusOK, Body: usersResponse},