diff --git a/app/app_client.go b/app/app_client.go new file mode 100644 index 00000000000..a75fa392f39 --- /dev/null +++ b/app/app_client.go @@ -0,0 +1,1241 @@ +// Package app contains the interfaces that manage a machine fleet with code instead of with the graphical interface of the Viam App. +// +// [fleet management docs]: https://docs.viam.com/appendix/apis/fleet/ +package app + +import ( + "context" + + packages "go.viam.com/api/app/packages/v1" + pb "go.viam.com/api/app/v1" + "go.viam.com/utils/protoutils" + "go.viam.com/utils/rpc" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// AppClient is a gRPC client for method calls to the App API. +// +//nolint:revive // stutter: Ignore the "stuttering" warning for this type name +type AppClient struct { + client pb.AppServiceClient +} + +// NewAppClient constructs a new AppClient using the connection passed in by the Viam client. +func NewAppClient(conn rpc.ClientConn) *AppClient { + return &AppClient{client: pb.NewAppServiceClient(conn)} +} + +// GetUserIDByEmail gets the ID of the user with the given email. +func (c *AppClient) GetUserIDByEmail(ctx context.Context, email string) (string, error) { + resp, err := c.client.GetUserIDByEmail(ctx, &pb.GetUserIDByEmailRequest{ + Email: email, + }) + if err != nil { + return "", err + } + return resp.UserId, nil +} + +// CreateOrganization creates a new organization. +func (c *AppClient) CreateOrganization(ctx context.Context, name string) (*Organization, error) { + resp, err := c.client.CreateOrganization(ctx, &pb.CreateOrganizationRequest{ + Name: name, + }) + if err != nil { + return nil, err + } + return organizationFromProto(resp.Organization), nil +} + +// ListOrganizations lists all the organizations. +func (c *AppClient) ListOrganizations(ctx context.Context) ([]*Organization, error) { + resp, err := c.client.ListOrganizations(ctx, &pb.ListOrganizationsRequest{}) + if err != nil { + return nil, err + } + + var organizations []*Organization + for _, org := range resp.Organizations { + organizations = append(organizations, organizationFromProto(org)) + } + return organizations, nil +} + +// GetOrganizationsWithAccessToLocation gets all the organizations that have access to a location. +func (c *AppClient) GetOrganizationsWithAccessToLocation(ctx context.Context, locationID string) ([]*OrganizationIdentity, error) { + resp, err := c.client.GetOrganizationsWithAccessToLocation(ctx, &pb.GetOrganizationsWithAccessToLocationRequest{ + LocationId: locationID, + }) + if err != nil { + return nil, err + } + + var organizations []*OrganizationIdentity + for _, org := range resp.OrganizationIdentities { + organizations = append(organizations, organizationIdentityFromProto(org)) + } + return organizations, nil +} + +// ListOrganizationsByUser lists all the organizations that a user belongs to. +func (c *AppClient) ListOrganizationsByUser(ctx context.Context, userID string) ([]*OrgDetails, error) { + resp, err := c.client.ListOrganizationsByUser(ctx, &pb.ListOrganizationsByUserRequest{ + UserId: userID, + }) + if err != nil { + return nil, err + } + + var organizations []*OrgDetails + for _, org := range resp.Orgs { + organizations = append(organizations, orgDetailsFromProto(org)) + } + return organizations, nil +} + +// GetOrganization gets an organization. +func (c *AppClient) GetOrganization(ctx context.Context, orgID string) (*Organization, error) { + resp, err := c.client.GetOrganization(ctx, &pb.GetOrganizationRequest{ + OrganizationId: orgID, + }) + if err != nil { + return nil, err + } + return organizationFromProto(resp.Organization), nil +} + +// GetOrganizationNamespaceAvailability checks for namespace availability throughout all organizations. +func (c *AppClient) GetOrganizationNamespaceAvailability(ctx context.Context, namespace string) (bool, error) { + resp, err := c.client.GetOrganizationNamespaceAvailability(ctx, &pb.GetOrganizationNamespaceAvailabilityRequest{ + PublicNamespace: namespace, + }) + if err != nil { + return false, err + } + return resp.Available, nil +} + +// UpdateOrganizationOptions contains optional parameters for UpdateOrganization. +type UpdateOrganizationOptions struct { + Name *string + Namespace *string + Region *string + CID *string +} + +// UpdateOrganization updates an organization. +func (c *AppClient) UpdateOrganization(ctx context.Context, orgID string, opts UpdateOrganizationOptions) (*Organization, error) { + resp, err := c.client.UpdateOrganization(ctx, &pb.UpdateOrganizationRequest{ + OrganizationId: orgID, + Name: opts.Name, + PublicNamespace: opts.Namespace, + Region: opts.Region, + Cid: opts.CID, + }) + if err != nil { + return nil, err + } + return organizationFromProto(resp.Organization), nil +} + +// DeleteOrganization deletes an organization. +func (c *AppClient) DeleteOrganization(ctx context.Context, orgID string) error { + _, err := c.client.DeleteOrganization(ctx, &pb.DeleteOrganizationRequest{ + OrganizationId: orgID, + }) + return err +} + +// ListOrganizationMembers lists all members of an organization and all invited members to the organization. +func (c *AppClient) ListOrganizationMembers(ctx context.Context, orgID string) ([]*OrganizationMember, []*OrganizationInvite, error) { + resp, err := c.client.ListOrganizationMembers(ctx, &pb.ListOrganizationMembersRequest{ + OrganizationId: orgID, + }) + if err != nil { + return nil, nil, err + } + + var members []*OrganizationMember + for _, member := range resp.Members { + members = append(members, organizationMemberFromProto(member)) + } + var invites []*OrganizationInvite + for _, invite := range resp.Invites { + invites = append(invites, organizationInviteFromProto(invite)) + } + return members, invites, nil +} + +// CreateOrganizationInviteOptions contains optional parameters for CreateOrganizationInvite. +type CreateOrganizationInviteOptions struct { + SendEmailInvite *bool +} + +// CreateOrganizationInvite creates an organization invite to an organization. +func (c *AppClient) CreateOrganizationInvite( + ctx context.Context, orgID, email string, authorizations []*Authorization, opts CreateOrganizationInviteOptions, +) (*OrganizationInvite, error) { + var pbAuthorizations []*pb.Authorization + for _, authorization := range authorizations { + pbAuthorizations = append(pbAuthorizations, authorizationToProto(authorization)) + } + resp, err := c.client.CreateOrganizationInvite(ctx, &pb.CreateOrganizationInviteRequest{ + OrganizationId: orgID, + Email: email, + Authorizations: pbAuthorizations, + SendEmailInvite: opts.SendEmailInvite, + }) + if err != nil { + return nil, err + } + return organizationInviteFromProto(resp.Invite), nil +} + +// UpdateOrganizationInviteAuthorizations updates the authorizations attached to an organization invite. +func (c *AppClient) UpdateOrganizationInviteAuthorizations( + ctx context.Context, orgID, email string, addAuthorizations, removeAuthorizations []*Authorization, +) (*OrganizationInvite, error) { + var pbAddAuthorizations []*pb.Authorization + for _, authorization := range addAuthorizations { + pbAddAuthorizations = append(pbAddAuthorizations, authorizationToProto(authorization)) + } + var pbRemoveAuthorizations []*pb.Authorization + for _, authorization := range removeAuthorizations { + pbRemoveAuthorizations = append(pbRemoveAuthorizations, authorizationToProto(authorization)) + } + resp, err := c.client.UpdateOrganizationInviteAuthorizations(ctx, &pb.UpdateOrganizationInviteAuthorizationsRequest{ + OrganizationId: orgID, + Email: email, + AddAuthorizations: pbAddAuthorizations, + RemoveAuthorizations: pbRemoveAuthorizations, + }) + if err != nil { + return nil, err + } + return organizationInviteFromProto(resp.Invite), nil +} + +// DeleteOrganizationMember deletes an organization member from an organization. +func (c *AppClient) DeleteOrganizationMember(ctx context.Context, orgID, userID string) error { + _, err := c.client.DeleteOrganizationMember(ctx, &pb.DeleteOrganizationMemberRequest{ + OrganizationId: orgID, + UserId: userID, + }) + return err +} + +// DeleteOrganizationInvite deletes an organization invite. +func (c *AppClient) DeleteOrganizationInvite(ctx context.Context, orgID, email string) error { + _, err := c.client.DeleteOrganizationInvite(ctx, &pb.DeleteOrganizationInviteRequest{ + OrganizationId: orgID, + Email: email, + }) + return err +} + +// ResendOrganizationInvite resends an organization invite. +func (c *AppClient) ResendOrganizationInvite(ctx context.Context, orgID, email string) (*OrganizationInvite, error) { + resp, err := c.client.ResendOrganizationInvite(ctx, &pb.ResendOrganizationInviteRequest{ + OrganizationId: orgID, + Email: email, + }) + if err != nil { + return nil, err + } + return organizationInviteFromProto(resp.Invite), nil +} + +// EnableBillingService enables a billing service to an address in an organization. +func (c *AppClient) EnableBillingService(ctx context.Context, orgID string, billingAddress *BillingAddress) error { + _, err := c.client.EnableBillingService(ctx, &pb.EnableBillingServiceRequest{ + OrgId: orgID, + BillingAddress: billingAddressToProto(billingAddress), + }) + return err +} + +// DisableBillingService disables the billing service for an organization. +func (c *AppClient) DisableBillingService(ctx context.Context, orgID string) error { + _, err := c.client.DisableBillingService(ctx, &pb.DisableBillingServiceRequest{ + OrgId: orgID, + }) + return err +} + +// UpdateBillingService updates the billing service of an organization. +func (c *AppClient) UpdateBillingService( + ctx context.Context, orgID string, billingAddress *BillingAddress, billingSupportEmail string, +) error { + _, err := c.client.UpdateBillingService(ctx, &pb.UpdateBillingServiceRequest{ + OrgId: orgID, + BillingAddress: billingAddressToProto(billingAddress), + BillingSupportEmail: billingSupportEmail, + }) + return err +} + +// OrganizationSetSupportEmail sets an organization's support email. +func (c *AppClient) OrganizationSetSupportEmail(ctx context.Context, orgID, email string) error { + _, err := c.client.OrganizationSetSupportEmail(ctx, &pb.OrganizationSetSupportEmailRequest{ + OrgId: orgID, + Email: email, + }) + return err +} + +// OrganizationGetSupportEmail gets an organization's support email. +func (c *AppClient) OrganizationGetSupportEmail(ctx context.Context, orgID string) (string, error) { + resp, err := c.client.OrganizationGetSupportEmail(ctx, &pb.OrganizationGetSupportEmailRequest{ + OrgId: orgID, + }) + if err != nil { + return "", err + } + return resp.Email, nil +} + +// CreateLocationOptions contains optional parameters for CreateLocation. +type CreateLocationOptions struct { + ParentLocationID *string +} + +// CreateLocation creates a location. +func (c *AppClient) CreateLocation(ctx context.Context, orgID, name string, opts CreateLocationOptions) (*Location, error) { + resp, err := c.client.CreateLocation(ctx, &pb.CreateLocationRequest{ + OrganizationId: orgID, + Name: name, + ParentLocationId: opts.ParentLocationID, + }) + if err != nil { + return nil, err + } + return locationFromProto(resp.Location), nil +} + +// GetLocation gets a location. +func (c *AppClient) GetLocation(ctx context.Context, locationID string) (*Location, error) { + resp, err := c.client.GetLocation(ctx, &pb.GetLocationRequest{ + LocationId: locationID, + }) + if err != nil { + return nil, err + } + return locationFromProto(resp.Location), nil +} + +// UpdateLocationOptions contains optional parameters for UpdateLocation. +type UpdateLocationOptions struct { + Name *string + ParentLocationID *string + Region *string +} + +// UpdateLocation updates a location. +func (c *AppClient) UpdateLocation(ctx context.Context, locationID string, opts UpdateLocationOptions) (*Location, error) { + resp, err := c.client.UpdateLocation(ctx, &pb.UpdateLocationRequest{ + LocationId: locationID, + Name: opts.Name, + ParentLocationId: opts.ParentLocationID, + Region: opts.Region, + }) + if err != nil { + return nil, err + } + return locationFromProto(resp.Location), nil +} + +// DeleteLocation deletes a location. +func (c *AppClient) DeleteLocation(ctx context.Context, locationID string) error { + _, err := c.client.DeleteLocation(ctx, &pb.DeleteLocationRequest{ + LocationId: locationID, + }) + return err +} + +// ListLocations gets a list of locations under the specified organization. +func (c *AppClient) ListLocations(ctx context.Context, orgID string) ([]*Location, error) { + resp, err := c.client.ListLocations(ctx, &pb.ListLocationsRequest{ + OrganizationId: orgID, + }) + if err != nil { + return nil, err + } + + var locations []*Location + for _, location := range resp.Locations { + locations = append(locations, locationFromProto(location)) + } + return locations, nil +} + +// ShareLocation shares a location with an organization. +func (c *AppClient) ShareLocation(ctx context.Context, locationID, orgID string) error { + _, err := c.client.ShareLocation(ctx, &pb.ShareLocationRequest{ + LocationId: locationID, + OrganizationId: orgID, + }) + return err +} + +// UnshareLocation stops sharing a location with an organization. +func (c *AppClient) UnshareLocation(ctx context.Context, locationID, orgID string) error { + _, err := c.client.UnshareLocation(ctx, &pb.UnshareLocationRequest{ + LocationId: locationID, + OrganizationId: orgID, + }) + return err +} + +// LocationAuth gets a location's authorization secrets. +func (c *AppClient) LocationAuth(ctx context.Context, locationID string) (*LocationAuth, error) { + resp, err := c.client.LocationAuth(ctx, &pb.LocationAuthRequest{ + LocationId: locationID, + }) + if err != nil { + return nil, err + } + return locationAuthFromProto(resp.Auth), nil +} + +// CreateLocationSecret creates a new generated secret in the location. Succeeds if there are no more than 2 active secrets after creation. +func (c *AppClient) CreateLocationSecret(ctx context.Context, locationID string) (*LocationAuth, error) { + resp, err := c.client.CreateLocationSecret(ctx, &pb.CreateLocationSecretRequest{ + LocationId: locationID, + }) + if err != nil { + return nil, err + } + return locationAuthFromProto(resp.Auth), nil +} + +// DeleteLocationSecret deletes a secret from the location. +func (c *AppClient) DeleteLocationSecret(ctx context.Context, locationID, secretID string) error { + _, err := c.client.DeleteLocationSecret(ctx, &pb.DeleteLocationSecretRequest{ + LocationId: locationID, + SecretId: secretID, + }) + return err +} + +// GetRobot gets a specific robot by ID. +func (c *AppClient) GetRobot(ctx context.Context, id string) (*Robot, error) { + resp, err := c.client.GetRobot(ctx, &pb.GetRobotRequest{ + Id: id, + }) + if err != nil { + return nil, err + } + return robotFromProto(resp.Robot), nil +} + +// GetRoverRentalRobots gets rover rental robots within an organization. +func (c *AppClient) GetRoverRentalRobots(ctx context.Context, orgID string) ([]*RoverRentalRobot, error) { + resp, err := c.client.GetRoverRentalRobots(ctx, &pb.GetRoverRentalRobotsRequest{ + OrgId: orgID, + }) + if err != nil { + return nil, err + } + var robots []*RoverRentalRobot + for _, robot := range resp.Robots { + robots = append(robots, roverRentalRobotFromProto(robot)) + } + return robots, nil +} + +// GetRobotParts gets a list of all the parts under a specific machine. +func (c *AppClient) GetRobotParts(ctx context.Context, robotID string) ([]*RobotPart, error) { + resp, err := c.client.GetRobotParts(ctx, &pb.GetRobotPartsRequest{ + RobotId: robotID, + }) + if err != nil { + return nil, err + } + var parts []*RobotPart + for _, part := range resp.Parts { + parts = append(parts, robotPartFromProto(part)) + } + return parts, nil +} + +// GetRobotPart gets a specific robot part and its config by ID. +func (c *AppClient) GetRobotPart(ctx context.Context, id string) (*RobotPart, string, error) { + resp, err := c.client.GetRobotPart(ctx, &pb.GetRobotPartRequest{ + Id: id, + }) + if err != nil { + return nil, "", err + } + return robotPartFromProto(resp.Part), resp.ConfigJson, nil +} + +// GetRobotPartLogsOptions contains optional parameters for GetRobotPartLogs. +type GetRobotPartLogsOptions struct { + Filter *string + PageToken *string + Levels []string + Start *timestamppb.Timestamp + End *timestamppb.Timestamp + Limit *int64 + Source *string +} + +// GetRobotPartLogs gets the logs associated with a robot part and the next page token, +// defaulting to the most recent page if pageToken is empty. Logs of all levels are returned when levels is empty. +func (c *AppClient) GetRobotPartLogs(ctx context.Context, id string, opts GetRobotPartLogsOptions) ([]*LogEntry, string, error) { + resp, err := c.client.GetRobotPartLogs(ctx, &pb.GetRobotPartLogsRequest{ + Id: id, + Filter: opts.Filter, + PageToken: opts.PageToken, + Levels: opts.Levels, + Start: opts.Start, + End: opts.End, + Limit: opts.Limit, + Source: opts.Source, + }) + if err != nil { + return nil, "", err + } + var logs []*LogEntry + for _, log := range resp.Logs { + logs = append(logs, logEntryFromProto(log)) + } + return logs, resp.NextPageToken, nil +} + +// RobotPartLogStream is a stream with robot part logs. +type RobotPartLogStream struct { + stream pb.AppService_TailRobotPartLogsClient +} + +// Next gets the next robot part log entry. +func (s *RobotPartLogStream) Next() ([]*LogEntry, error) { + streamResp, err := s.stream.Recv() + if err != nil { + return nil, err + } + + var logs []*LogEntry + for _, log := range streamResp.Logs { + logs = append(logs, logEntryFromProto(log)) + } + return logs, nil +} + +// TailRobotPartLogsOptions contains optional parameters for TailRobotPartLogs. +type TailRobotPartLogsOptions struct { + Filter *string +} + +// TailRobotPartLogs gets a stream of log entries for a specific robot part. Logs are ordered by newest first. +func (c *AppClient) TailRobotPartLogs( + ctx context.Context, id string, errorsOnly bool, opts TailRobotPartLogsOptions, +) (*RobotPartLogStream, error) { + stream, err := c.client.TailRobotPartLogs(ctx, &pb.TailRobotPartLogsRequest{ + Id: id, + ErrorsOnly: errorsOnly, + Filter: opts.Filter, + }) + if err != nil { + return nil, err + } + return &RobotPartLogStream{stream: stream}, nil +} + +// GetRobotPartHistory gets a specific robot part history by ID. +func (c *AppClient) GetRobotPartHistory(ctx context.Context, id string) ([]*RobotPartHistoryEntry, error) { + resp, err := c.client.GetRobotPartHistory(ctx, &pb.GetRobotPartHistoryRequest{ + Id: id, + }) + if err != nil { + return nil, err + } + var history []*RobotPartHistoryEntry + for _, entry := range resp.History { + history = append(history, robotPartHistoryEntryFromProto(entry)) + } + return history, nil +} + +// UpdateRobotPart updates a robot part. +func (c *AppClient) UpdateRobotPart(ctx context.Context, id, name string, robotConfig interface{}) (*RobotPart, error) { + config, err := protoutils.StructToStructPb(robotConfig) + if err != nil { + return nil, err + } + resp, err := c.client.UpdateRobotPart(ctx, &pb.UpdateRobotPartRequest{ + Id: id, + Name: name, + RobotConfig: config, + }) + if err != nil { + return nil, err + } + return robotPartFromProto(resp.Part), nil +} + +// NewRobotPart creates a new robot part and returns its ID. +func (c *AppClient) NewRobotPart(ctx context.Context, robotID, partName string) (string, error) { + resp, err := c.client.NewRobotPart(ctx, &pb.NewRobotPartRequest{ + RobotId: robotID, + PartName: partName, + }) + if err != nil { + return "", err + } + return resp.PartId, nil +} + +// DeleteRobotPart deletes a robot part. +func (c *AppClient) DeleteRobotPart(ctx context.Context, partID string) error { + _, err := c.client.DeleteRobotPart(ctx, &pb.DeleteRobotPartRequest{ + PartId: partID, + }) + return err +} + +// GetRobotAPIKeys gets the robot API keys for the robot. +func (c *AppClient) GetRobotAPIKeys(ctx context.Context, robotID string) ([]*APIKeyWithAuthorizations, error) { + resp, err := c.client.GetRobotAPIKeys(ctx, &pb.GetRobotAPIKeysRequest{ + RobotId: robotID, + }) + if err != nil { + return nil, err + } + var keys []*APIKeyWithAuthorizations + for _, key := range resp.ApiKeys { + keys = append(keys, apiKeyWithAuthorizationsFromProto(key)) + } + return keys, nil +} + +// MarkPartAsMain marks the given part as the main part, and all the others as not. +func (c *AppClient) MarkPartAsMain(ctx context.Context, partID string) error { + _, err := c.client.MarkPartAsMain(ctx, &pb.MarkPartAsMainRequest{ + PartId: partID, + }) + return err +} + +// MarkPartForRestart marks the given part for restart. +// Once the robot part checks-in with the app the flag is reset on the robot part. +// Calling this multiple times before a robot part checks-in has no effect. +func (c *AppClient) MarkPartForRestart(ctx context.Context, partID string) error { + _, err := c.client.MarkPartForRestart(ctx, &pb.MarkPartForRestartRequest{ + PartId: partID, + }) + return err +} + +// CreateRobotPartSecret creates a new generated secret in the robot part. +// Succeeds if there are no more than 2 active secrets after creation. +func (c *AppClient) CreateRobotPartSecret(ctx context.Context, partID string) (*RobotPart, error) { + resp, err := c.client.CreateRobotPartSecret(ctx, &pb.CreateRobotPartSecretRequest{ + PartId: partID, + }) + if err != nil { + return nil, err + } + return robotPartFromProto(resp.Part), nil +} + +// DeleteRobotPartSecret deletes a secret from the robot part. +func (c *AppClient) DeleteRobotPartSecret(ctx context.Context, partID, secretID string) error { + _, err := c.client.DeleteRobotPartSecret(ctx, &pb.DeleteRobotPartSecretRequest{ + PartId: partID, + SecretId: secretID, + }) + return err +} + +// ListRobots gets a list of robots under a location. +func (c *AppClient) ListRobots(ctx context.Context, locationID string) ([]*Robot, error) { + resp, err := c.client.ListRobots(ctx, &pb.ListRobotsRequest{ + LocationId: locationID, + }) + if err != nil { + return nil, err + } + var robots []*Robot + for _, robot := range resp.Robots { + robots = append(robots, robotFromProto(robot)) + } + return robots, nil +} + +// NewRobot creates a new robot and returns its ID. +func (c *AppClient) NewRobot(ctx context.Context, name, location string) (string, error) { + resp, err := c.client.NewRobot(ctx, &pb.NewRobotRequest{ + Name: name, + Location: location, + }) + if err != nil { + return "", err + } + return resp.Id, nil +} + +// UpdateRobot updates a robot. +func (c *AppClient) UpdateRobot(ctx context.Context, id, name, location string) (*Robot, error) { + resp, err := c.client.UpdateRobot(ctx, &pb.UpdateRobotRequest{ + Id: id, + Name: name, + Location: location, + }) + if err != nil { + return nil, err + } + return robotFromProto(resp.Robot), nil +} + +// DeleteRobot deletes a robot. +func (c *AppClient) DeleteRobot(ctx context.Context, id string) error { + _, err := c.client.DeleteRobot(ctx, &pb.DeleteRobotRequest{ + Id: id, + }) + return err +} + +// ListFragments gets a list of fragments. +func (c *AppClient) ListFragments( + ctx context.Context, orgID string, showPublic bool, fragmentVisibility []FragmentVisibility, +) ([]*Fragment, error) { + var visibilities []pb.FragmentVisibility + for _, visibility := range fragmentVisibility { + pbFragmentVisibility := fragmentVisibilityToProto(visibility) + visibilities = append(visibilities, pbFragmentVisibility) + } + resp, err := c.client.ListFragments(ctx, &pb.ListFragmentsRequest{ + OrganizationId: orgID, + ShowPublic: showPublic, + FragmentVisibility: visibilities, + }) + if err != nil { + return nil, err + } + var fragments []*Fragment + for _, fragment := range resp.Fragments { + fragments = append(fragments, fragmentFromProto(fragment)) + } + return fragments, nil +} + +// GetFragment gets a single fragment. +func (c *AppClient) GetFragment(ctx context.Context, id string) (*Fragment, error) { + resp, err := c.client.GetFragment(ctx, &pb.GetFragmentRequest{ + Id: id, + }) + if err != nil { + return nil, err + } + return fragmentFromProto(resp.Fragment), nil +} + +// CreateFragmentOptions contains optional parameters for CreateFragment. +type CreateFragmentOptions struct { + Visibility *FragmentVisibility +} + +// CreateFragment creates a fragment. +func (c *AppClient) CreateFragment( + ctx context.Context, orgID, name string, config map[string]interface{}, opts CreateFragmentOptions, +) (*Fragment, error) { + pbConfig, err := protoutils.StructToStructPb(config) + if err != nil { + return nil, err + } + pbFragmentVisibility := fragmentVisibilityToProto(*opts.Visibility) + resp, err := c.client.CreateFragment(ctx, &pb.CreateFragmentRequest{ + Name: name, + Config: pbConfig, + OrganizationId: orgID, + Visibility: &pbFragmentVisibility, + }) + if err != nil { + return nil, err + } + return fragmentFromProto(resp.Fragment), nil +} + +// UpdateFragmentOptions contains optional parameters for UpdateFragment. +type UpdateFragmentOptions struct { + public *bool + visibility *FragmentVisibility +} + +// UpdateFragment updates a fragment. +func (c *AppClient) UpdateFragment( + ctx context.Context, id, name string, config map[string]interface{}, opts UpdateFragmentOptions, +) (*Fragment, error) { + cfg, err := protoutils.StructToStructPb(config) + if err != nil { + return nil, err + } + pbVisibility := fragmentVisibilityToProto(*opts.visibility) + resp, err := c.client.UpdateFragment(ctx, &pb.UpdateFragmentRequest{ + Id: id, + Name: name, + Config: cfg, + Public: opts.public, + Visibility: &pbVisibility, + }) + if err != nil { + return nil, err + } + return fragmentFromProto(resp.Fragment), nil +} + +// DeleteFragment deletes a fragment. +func (c *AppClient) DeleteFragment(ctx context.Context, id string) error { + _, err := c.client.DeleteFragment(ctx, &pb.DeleteFragmentRequest{ + Id: id, + }) + return err +} + +// ListMachineFragmentsOptions contains optional parameters for ListMachineFragments. +type ListMachineFragmentsOptions struct { + AdditionalFragmentIDs []string +} + +// ListMachineFragments gets top level and nested fragments for a amchine, as well as any other fragments specified by IDs. Additional +// fragments are useful when needing to view fragments that will be provisionally added to the machine alongside existing fragments. +func (c *AppClient) ListMachineFragments(ctx context.Context, machineID string, opts ListMachineFragmentsOptions) ([]*Fragment, error) { + resp, err := c.client.ListMachineFragments(ctx, &pb.ListMachineFragmentsRequest{ + MachineId: machineID, + AdditionalFragmentIds: opts.AdditionalFragmentIDs, + }) + if err != nil { + return nil, err + } + var fragments []*Fragment + for _, fragment := range resp.Fragments { + fragments = append(fragments, fragmentFromProto(fragment)) + } + return fragments, nil +} + +// GetFragmentHistoryOptions contains optional parameters for GetFragmentHistory. +type GetFragmentHistoryOptions struct { + PageToken *string + PageLimit *int64 +} + +// GetFragmentHistory gets the fragment's history and the next page token. +func (c *AppClient) GetFragmentHistory( + ctx context.Context, id string, opts GetFragmentHistoryOptions, +) ([]*FragmentHistoryEntry, string, error) { + resp, err := c.client.GetFragmentHistory(ctx, &pb.GetFragmentHistoryRequest{ + Id: id, + PageToken: opts.PageToken, + PageLimit: opts.PageLimit, + }) + if err != nil { + return nil, "", err + } + var history []*FragmentHistoryEntry + for _, entry := range resp.History { + history = append(history, fragmentHistoryEntryFromProto(entry)) + } + return history, resp.NextPageToken, nil +} + +// AddRole creates an identity authorization. +func (c *AppClient) AddRole(ctx context.Context, orgID, identityID, role, resourceType, resourceID string) error { + authorization, err := createAuthorization(orgID, identityID, "", role, resourceType, resourceID) + if err != nil { + return err + } + _, err = c.client.AddRole(ctx, &pb.AddRoleRequest{ + Authorization: authorization, + }) + return err +} + +// RemoveRole deletes an identity authorization. +func (c *AppClient) RemoveRole(ctx context.Context, authorization *Authorization) error { + _, err := c.client.RemoveRole(ctx, &pb.RemoveRoleRequest{ + Authorization: authorizationToProto(authorization), + }) + return err +} + +// ChangeRole changes an identity authorization to a new identity authorization. +func (c *AppClient) ChangeRole( + ctx context.Context, + oldAuthorization *Authorization, + newOrgID, + newIdentityID, + newRole, + newResourceType, + newResourceID string, +) error { + newAuthorization, err := createAuthorization(newOrgID, newIdentityID, "", newRole, newResourceType, newResourceID) + if err != nil { + return err + } + _, err = c.client.ChangeRole(ctx, &pb.ChangeRoleRequest{ + OldAuthorization: authorizationToProto(oldAuthorization), + NewAuthorization: newAuthorization, + }) + return err +} + +// ListAuthorizationsOptions contains optional parameters for ListAuthorizations. +type ListAuthorizationsOptions struct { + ResourceIDs []string +} + +// ListAuthorizations returns all authorization roles for any given resources. +// If no resources are given, all resources within the organization will be included. +func (c *AppClient) ListAuthorizations(ctx context.Context, orgID string, opts ListAuthorizationsOptions) ([]*Authorization, error) { + resp, err := c.client.ListAuthorizations(ctx, &pb.ListAuthorizationsRequest{ + OrganizationId: orgID, + ResourceIds: opts.ResourceIDs, + }) + if err != nil { + return nil, err + } + var authorizations []*Authorization + for _, authorization := range resp.Authorizations { + authorizations = append(authorizations, authorizationFromProto(authorization)) + } + return authorizations, nil +} + +// CheckPermissions checks the validity of a list of permissions. +func (c *AppClient) CheckPermissions(ctx context.Context, permissions []*AuthorizedPermissions) ([]*AuthorizedPermissions, error) { + var pbPermissions []*pb.AuthorizedPermissions + for _, permission := range permissions { + pbPermissions = append(pbPermissions, authorizedPermissionsToProto(permission)) + } + + resp, err := c.client.CheckPermissions(ctx, &pb.CheckPermissionsRequest{ + Permissions: pbPermissions, + }) + if err != nil { + return nil, err + } + + var authorizedPermissions []*AuthorizedPermissions + for _, permission := range resp.AuthorizedPermissions { + authorizedPermissions = append(authorizedPermissions, authorizedPermissionsFromProto(permission)) + } + return authorizedPermissions, nil +} + +// GetRegistryItem gets a registry item. +func (c *AppClient) GetRegistryItem(ctx context.Context, itemID string) (*RegistryItem, error) { + resp, err := c.client.GetRegistryItem(ctx, &pb.GetRegistryItemRequest{ + ItemId: itemID, + }) + if err != nil { + return nil, err + } + item, err := registryItemFromProto(resp.Item) + if err != nil { + return nil, err + } + return item, nil +} + +// CreateRegistryItem creates a registry item. +func (c *AppClient) CreateRegistryItem(ctx context.Context, orgID, name string, packageType PackageType) error { + _, err := c.client.CreateRegistryItem(ctx, &pb.CreateRegistryItemRequest{ + OrganizationId: orgID, + Name: name, + Type: packageTypeToProto(packageType), + }) + return err +} + +// UpdateRegistryItemOptions contains optional parameters for UpdateRegistryItem. +type UpdateRegistryItemOptions struct { + URL *string +} + +// UpdateRegistryItem updates a registry item. +func (c *AppClient) UpdateRegistryItem( + ctx context.Context, itemID string, packageType PackageType, description string, visibility Visibility, opts UpdateRegistryItemOptions, +) error { + _, err := c.client.UpdateRegistryItem(ctx, &pb.UpdateRegistryItemRequest{ + ItemId: itemID, + Type: packageTypeToProto(packageType), + Description: description, + Visibility: visibilityToProto(visibility), + Url: opts.URL, + }) + return err +} + +// ListRegistryItemsOptions contains optional parameters for ListRegistryItems. +type ListRegistryItemsOptions struct { + Types []PackageType + Visibilities []Visibility + Platforms []string + Statuses []RegistryItemStatus + SearchTerm *string + PageToken *string + PublicNamespaces []string +} + +// ListRegistryItems lists the registry items in an organization. +func (c *AppClient) ListRegistryItems(ctx context.Context, orgID *string, opts ListRegistryItemsOptions) ([]*RegistryItem, error) { + var pbTypes []packages.PackageType + for _, packageType := range opts.Types { + pbTypes = append(pbTypes, packageTypeToProto(packageType)) + } + var pbVisibilities []pb.Visibility + for _, visibility := range opts.Visibilities { + pbVisibilities = append(pbVisibilities, visibilityToProto(visibility)) + } + var pbStatuses []pb.RegistryItemStatus + for _, status := range opts.Statuses { + pbStatuses = append(pbStatuses, registryItemStatusToProto(status)) + } + resp, err := c.client.ListRegistryItems(ctx, &pb.ListRegistryItemsRequest{ + OrganizationId: orgID, + Types: pbTypes, + Visibilities: pbVisibilities, + Platforms: opts.Platforms, + Statuses: pbStatuses, + SearchTerm: opts.SearchTerm, + PageToken: opts.PageToken, + PublicNamespaces: opts.PublicNamespaces, + }) + if err != nil { + return nil, err + } + var items []*RegistryItem + for _, item := range resp.Items { + i, err := registryItemFromProto(item) + if err != nil { + return nil, err + } + items = append(items, i) + } + return items, nil +} + +// DeleteRegistryItem deletes a registry item given an ID that is formatted as `prefix:name“ +// where `prefix“ is the owner's organization ID or namespace. +func (c *AppClient) DeleteRegistryItem(ctx context.Context, itemID string) error { + _, err := c.client.DeleteRegistryItem(ctx, &pb.DeleteRegistryItemRequest{ + ItemId: itemID, + }) + return err +} + +// TransferRegistryItem transfers a registry item to a namespace. +func (c *AppClient) TransferRegistryItem(ctx context.Context, itemID, newPublicNamespace string) error { + _, err := c.client.TransferRegistryItem(ctx, &pb.TransferRegistryItemRequest{ + ItemId: itemID, + NewPublicNamespace: newPublicNamespace, + }) + return err +} + +// CreateModule creates a module and returns its ID and URL. +func (c *AppClient) CreateModule(ctx context.Context, orgID, name string) (string, string, error) { + resp, err := c.client.CreateModule(ctx, &pb.CreateModuleRequest{ + OrganizationId: orgID, + Name: name, + }) + if err != nil { + return "", "", err + } + return resp.ModuleId, resp.Url, nil +} + +// UpdateModuleOptions contains optional parameters for UpdateModule. +type UpdateModuleOptions struct { + firstRun *string +} + +// UpdateModule updates the documentation URL, description, models, entrypoint, and/or the visibility of a module and returns its URL. +// A path to a setup script can be added that is run before a newly downloaded module starts. +func (c *AppClient) UpdateModule( + ctx context.Context, + moduleID string, + visibility Visibility, + url, + description string, + models []*Model, + entrypoint string, + opts UpdateModuleOptions, +) (string, error) { + var pbModels []*pb.Model + for _, model := range models { + pbModels = append(pbModels, modelToProto(model)) + } + resp, err := c.client.UpdateModule(ctx, &pb.UpdateModuleRequest{ + ModuleId: moduleID, + Visibility: visibilityToProto(visibility), + Url: url, + Description: description, + Models: pbModels, + Entrypoint: entrypoint, + FirstRun: opts.firstRun, + }) + if err != nil { + return "", err + } + return resp.Url, nil +} + +// UploadModuleFile uploads a module file and returns the URL of the uploaded file. +func (c *AppClient) UploadModuleFile(ctx context.Context, fileInfo ModuleFileInfo, file []byte) (string, error) { + stream, err := c.client.UploadModuleFile(ctx) + if err != nil { + return "", err + } + + err = stream.Send(&pb.UploadModuleFileRequest{ + ModuleFile: &pb.UploadModuleFileRequest_ModuleFileInfo{ + ModuleFileInfo: moduleFileInfoToProto(&fileInfo), + }, + }) + if err != nil { + return "", err + } + + uploadChunkSize := 64 * 1024 // 64 kB in bytes + for start := 0; start < len(file); start += uploadChunkSize { + if ctx.Err() != nil { + return "", ctx.Err() + } + + end := start + uploadChunkSize + if end > len(file) { + end = len(file) + } + + chunk := file[start:end] + err := stream.Send(&pb.UploadModuleFileRequest{ + ModuleFile: &pb.UploadModuleFileRequest_File{ + File: chunk, + }, + }) + if err != nil { + return "", err + } + } + + resp, err := stream.CloseAndRecv() + if err != nil { + return "", err + } + return resp.Url, err +} + +// GetModule gets a module. +func (c *AppClient) GetModule(ctx context.Context, moduleID string) (*Module, error) { + resp, err := c.client.GetModule(ctx, &pb.GetModuleRequest{ + ModuleId: moduleID, + }) + if err != nil { + return nil, err + } + return moduleFromProto(resp.Module), nil +} + +// ListModulesOptions contains optional parameters for ListModules. +type ListModulesOptions struct { + orgID *string +} + +// ListModules lists the modules in the organization. +func (c *AppClient) ListModules(ctx context.Context, opts ListModulesOptions) ([]*Module, error) { + resp, err := c.client.ListModules(ctx, &pb.ListModulesRequest{ + OrganizationId: opts.orgID, + }) + if err != nil { + return nil, err + } + var modules []*Module + for _, module := range resp.Modules { + modules = append(modules, moduleFromProto(module)) + } + return modules, nil +} + +// CreateKey creates a new API key associated with a list of authorizations and returns its key and ID. +func (c *AppClient) CreateKey( + ctx context.Context, orgID string, keyAuthorizations []APIKeyAuthorization, name string, +) (string, string, error) { + var authorizations []*pb.Authorization + for _, keyAuthorization := range keyAuthorizations { + authorization, err := createAuthorization( + orgID, "", "api-key", keyAuthorization.role, keyAuthorization.resourceType, keyAuthorization.resourceID) + if err != nil { + return "", "", err + } + authorizations = append(authorizations, authorization) + } + + resp, err := c.client.CreateKey(ctx, &pb.CreateKeyRequest{ + Authorizations: authorizations, + Name: name, + }) + if err != nil { + return "", "", err + } + return resp.Key, resp.Id, nil +} + +// DeleteKey deletes an API key. +func (c *AppClient) DeleteKey(ctx context.Context, id string) error { + _, err := c.client.DeleteKey(ctx, &pb.DeleteKeyRequest{ + Id: id, + }) + return err +} + +// ListKeys lists all the keys for the organization. +func (c *AppClient) ListKeys(ctx context.Context, orgID string) ([]*APIKeyWithAuthorizations, error) { + resp, err := c.client.ListKeys(ctx, &pb.ListKeysRequest{ + OrgId: orgID, + }) + if err != nil { + return nil, err + } + var apiKeys []*APIKeyWithAuthorizations + for _, key := range resp.ApiKeys { + apiKeys = append(apiKeys, apiKeyWithAuthorizationsFromProto(key)) + } + return apiKeys, nil +} + +// RenameKey renames an API key and returns its ID and name. +func (c *AppClient) RenameKey(ctx context.Context, id, name string) (string, string, error) { + resp, err := c.client.RenameKey(ctx, &pb.RenameKeyRequest{ + Id: id, + Name: name, + }) + if err != nil { + return "", "", err + } + return resp.Id, resp.Name, nil +} + +// RotateKey rotates an API key and returns its ID and key. +func (c *AppClient) RotateKey(ctx context.Context, id string) (string, string, error) { + resp, err := c.client.RotateKey(ctx, &pb.RotateKeyRequest{ + Id: id, + }) + if err != nil { + return "", "", err + } + return resp.Id, resp.Key, nil +} + +// CreateKeyFromExistingKeyAuthorizations creates a new API key with an existing key's authorizations and returns its ID and key. +func (c *AppClient) CreateKeyFromExistingKeyAuthorizations(ctx context.Context, id string) (string, string, error) { + resp, err := c.client.CreateKeyFromExistingKeyAuthorizations(ctx, &pb.CreateKeyFromExistingKeyAuthorizationsRequest{ + Id: id, + }) + if err != nil { + return "", "", err + } + return resp.Id, resp.Key, nil +} diff --git a/app/app_client_test.go b/app/app_client_test.go new file mode 100644 index 00000000000..bb03da0e075 --- /dev/null +++ b/app/app_client_test.go @@ -0,0 +1,1928 @@ +package app + +import ( + "context" + "fmt" + "testing" + + mlTraining "go.viam.com/api/app/mltraining/v1" + packages "go.viam.com/api/app/packages/v1" + pb "go.viam.com/api/app/v1" + common "go.viam.com/api/common/v1" + "go.viam.com/test" + "go.viam.com/utils/protoutils" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" + + "go.viam.com/rdk/testutils/inject" +) + +const ( + organizationID2 = "organization_id_2" + email = "email" + userID = "user_id" + available = true + authorizationType = "owner" + authorizationType2 = "operator" + badAuthorizationType = "authorization_type" + resourceType = "organization" + resourceType2 = "location" + badResourceType = "resource_type" + resourceID = "resource_id" + resourceID2 = "resource_id_2" + identityID = "identity_id" + identityID2 = "identity_id_2" + identityType = "" + secretID = "secret_ids" + primary = true + robotCount = 1 + robotLocation = "robot_location" + dnsName = "dns_name" + secret = "secret" + mainPart = false + fqdn = "fqdn" + localFQDN = "local_fqdn" + configJSON = "configJson" + host = "host" + level = "level" + loggerName = "logger_name" + message = "message" + stack = "stack" + value = "value" + isDeactivated = false + keyID = "key_id" + key = "key" + fragmentID = "fragment_id" + organizationOwner = "organization_owner" + robotPartCount = 5 + onlyUsedByOwner = false + organizationCount = 2 + permission = "permission" + itemID = "item_id" + description = "description" + packageType = PackageTypeMLTraining + visibility = VisibilityPublic + totalRobotUsage = 4 + totalExternalRobotUsage = 2 + totalOrganizationUsage = 40 + totalExternalOrganizationUsage = 52 + version = "version" + modelType = ModelTypeObjectDetection + modelFramework = ModelFrameworkPyTorch + draft = false + platform = "platform" + registryItemStatus = RegistryItemStatusPublished + moduleID = "module_id" + api = "api" + modelString = "model_string" + entryPoint = "entry_point" + errorsOnly = true +) + +var ( + organizationID = "organization_id" + name = "name" + region = "region" + namespace = "public_namespace" + cid = "cid" + dateAdded = timestamppb.Timestamp{Seconds: 0, Nanos: 50} + organization = Organization{ + ID: organizationID, + Name: name, + CreatedOn: &dateAdded, + PublicNamespace: namespace, + DefaultRegion: region, + Cid: &cid, + } + pbOrganization = pb.Organization{ + Id: organization.ID, + Name: organization.Name, + CreatedOn: organization.CreatedOn, + PublicNamespace: organization.PublicNamespace, + DefaultRegion: organization.DefaultRegion, + Cid: organization.Cid, + } + organizationIdentity = OrganizationIdentity{ + ID: organizationID, + Name: name, + } + orgDetails = OrgDetails{ + OrgID: organizationID, + OrgName: name, + } + lastLogin = timestamppb.Timestamp{Seconds: 0, Nanos: 100} + createdOn = timestamppb.Timestamp{Seconds: 0, Nanos: 0} + authorization = Authorization{ + AuthorizationType: authorizationType, + AuthorizationID: authorizationID, + ResourceType: resourceType, + ResourceID: resourceID, + IdentityID: identityID, + OrganizationID: organizationID, + IdentityType: identityType, + } + pbAuthorization = pb.Authorization{ + AuthorizationType: authorization.AuthorizationType, + AuthorizationId: authorization.AuthorizationID, + ResourceType: authorization.ResourceType, + ResourceId: authorization.ResourceID, + IdentityId: authorization.IdentityID, + OrganizationId: authorization.OrganizationID, + IdentityType: authorization.IdentityType, + } + authorization2 = Authorization{ + AuthorizationType: authorizationType2, + AuthorizationID: authorizationID2, + ResourceType: resourceType2, + ResourceID: resourceID2, + IdentityID: identityID2, + OrganizationID: organizationID2, + IdentityType: identityType, + } + pbAuthorization2 = pb.Authorization{ + AuthorizationType: authorization2.AuthorizationType, + AuthorizationId: authorization2.AuthorizationID, + ResourceType: authorization2.ResourceType, + ResourceId: authorization2.ResourceID, + IdentityId: authorization2.IdentityID, + OrganizationId: authorization2.OrganizationID, + IdentityType: authorization2.IdentityType, + } + authorizations = []*Authorization{&authorization, &authorization2} + pbAuthorizations = []*pb.Authorization{&pbAuthorization, &pbAuthorization2} + member = OrganizationMember{ + UserID: userID, + Emails: []string{email}, + DateAdded: &dateAdded, + LastLogin: &lastLogin, + } + invite = OrganizationInvite{ + OrganizationID: organizationID, + Email: email, + CreatedOn: &createdOn, + Authorizations: authorizations, + } + pbInvite = pb.OrganizationInvite{ + OrganizationId: invite.OrganizationID, + Email: invite.Email, + CreatedOn: invite.CreatedOn, + Authorizations: pbAuthorizations, + } + sendEmailInvite = true + addressLine2 = "address_line_2" + address = BillingAddress{ + AddressLine1: "address_line_1", + AddressLine2: &addressLine2, + City: "city", + State: "state", + } + pbAddress = pb.BillingAddress{ + AddressLine_1: address.AddressLine1, + AddressLine_2: address.AddressLine2, + City: address.City, + State: address.State, + } + parentLocationID = "parent_location_id" + sharedSecret = SharedSecret{ + ID: secretID, + CreatedOn: &createdOn, + State: SharedSecretStateEnabled, + } + sharedSecrets = []*SharedSecret{&sharedSecret} + pbSecret = pb.SharedSecret{ + Id: sharedSecret.ID, + CreatedOn: sharedSecret.CreatedOn, + State: sharedSecretStateToProto(sharedSecret.State), + } + pbSecrets = []*pb.SharedSecret{&pbSecret} + locationAuth = LocationAuth{ + LocationID: locationID, + Secrets: sharedSecrets, + } + pbLocationAuth = pb.LocationAuth{ + LocationId: locationAuth.LocationID, + Secrets: pbSecrets, + } + locationOrg = LocationOrganization{ + OrganizationID: organizationID, + Primary: primary, + } + storageConfig = StorageConfig{ + Region: region, + } + location = Location{ + ID: locationID, + Name: name, + ParentLocationID: parentLocationID, + Auth: &locationAuth, + Organizations: []*LocationOrganization{&locationOrg}, + CreatedOn: &createdOn, + RobotCount: robotCount, + Config: &storageConfig, + } + pbLocation = pb.Location{ + Id: location.ID, + Name: location.Name, + ParentLocationId: location.ParentLocationID, + Auth: &pbLocationAuth, + Organizations: []*pb.LocationOrganization{ + { + OrganizationId: locationOrg.OrganizationID, + Primary: locationOrg.Primary, + }, + }, + CreatedOn: location.CreatedOn, + RobotCount: location.RobotCount, + Config: &pb.StorageConfig{ + Region: storageConfig.Region, + }, + } + lastAccess = timestamppb.Timestamp{Seconds: 0, Nanos: 110} + robot = Robot{ + ID: robotID, + Name: name, + Location: robotLocation, + LastAccess: &lastAccess, + CreatedOn: &createdOn, + } + pbRobot = pb.Robot{ + Id: robot.ID, + Name: robot.Name, + Location: robot.Location, + LastAccess: robot.LastAccess, + CreatedOn: robot.CreatedOn, + } + roverRentalRobot = RoverRentalRobot{ + RobotID: robotID, + LocationID: locationID, + RobotName: name, + RobotMainPartID: partID, + } + lastUpdated = timestamppb.Timestamp{Seconds: 0, Nanos: 130} + robotConfig = map[string]interface{}{"name": name, "ID": robotID} + pbRobotConfig, _ = protoutils.StructToStructPb(*robotPart.RobotConfig) + pbUserSuppliedInfo, _ = protoutils.StructToStructPb(*robotPart.UserSuppliedInfo) + userSuppliedInfo = map[string]interface{}{"userID": userID} + robotPart = RobotPart{ + ID: partID, + Name: name, + DNSName: dnsName, + Secret: secret, + Robot: robotID, + LocationID: locationID, + RobotConfig: &robotConfig, + LastAccess: &lastAccess, + UserSuppliedInfo: &userSuppliedInfo, + MainPart: mainPart, + FQDN: fqdn, + LocalFQDN: localFQDN, + CreatedOn: &createdOn, + Secrets: sharedSecrets, + LastUpdated: &lastUpdated, + } + pbRobotPart = pb.RobotPart{ + Id: robotPart.ID, + Name: robotPart.Name, + DnsName: robotPart.DNSName, + Secret: robotPart.Secret, + Robot: robotPart.Robot, + LocationId: robotPart.LocationID, + RobotConfig: pbRobotConfig, + LastAccess: robotPart.LastAccess, + UserSuppliedInfo: pbUserSuppliedInfo, + MainPart: robotPart.MainPart, + Fqdn: robotPart.FQDN, + LocalFqdn: robotPart.LocalFQDN, + CreatedOn: robotPart.CreatedOn, + Secrets: pbSecrets, + LastUpdated: robotPart.LastUpdated, + } + pageToken = "page_token" + levels = []string{level} + start = timestamppb.Timestamp{Seconds: 92, Nanos: 0} + end = timestamppb.Timestamp{Seconds: 99, Nanos: 999} + int64Limit int64 = 2 + source = "source" + filter = "filter" + timestamp = timestamppb.Timestamp{Seconds: 11, Nanos: 15} + caller = map[string]interface{}{"name": name} + field = map[string]interface{}{"key": "value"} + logEntry = LogEntry{ + Host: host, + Level: level, + Time: ×tamp, + LoggerName: loggerName, + Message: message, + Caller: &caller, + Stack: stack, + Fields: []*map[string]interface{}{&field}, + } + pbCaller, _ = protoutils.StructToStructPb(*logEntry.Caller) + pbField, _ = protoutils.StructToStructPb(field) + pbLogEntry = common.LogEntry{ + Host: logEntry.Host, + Level: logEntry.Level, + Time: logEntry.Time, + LoggerName: logEntry.LoggerName, + Message: logEntry.Message, + Caller: pbCaller, + Stack: logEntry.Stack, + Fields: []*structpb.Struct{pbField}, + } + logEntries = []*LogEntry{&logEntry} + authenticatorInfo = AuthenticatorInfo{ + Type: AuthenticationTypeAPIKey, + Value: value, + IsDeactivated: isDeactivated, + } + pbAuthenticatorInfo = pb.AuthenticatorInfo{ + Type: authenticationTypeToProto(authenticatorInfo.Type), + Value: authenticatorInfo.Value, + IsDeactivated: authenticatorInfo.IsDeactivated, + } + robotPartHistoryEntry = RobotPartHistoryEntry{ + Part: partID, + Robot: robotID, + When: ×tamp, + Old: &robotPart, + EditedBy: &authenticatorInfo, + } + authorizationID = fmt.Sprintf("%s_%s", resourceType, authorizationType) + authorizationID2 = fmt.Sprintf("%s_%s", resourceType2, authorizationType2) + authorizationDetails = AuthorizationDetails{ + AuthorizationType: authorizationType, + AuthorizationID: authorizationID, + ResourceType: resourceType, + ResourceID: resourceID, + OrgID: organizationID, + } + apiKeyWithAuthorizations = APIKeyWithAuthorizations{ + APIKey: &APIKey{ + ID: keyID, + Key: key, + Name: name, + CreatedOn: &createdOn, + }, + Authorizations: []*AuthorizationDetails{&authorizationDetails}, + } + pbAPIKeyWithAuthorizations = pb.APIKeyWithAuthorizations{ + ApiKey: &pb.APIKey{ + Id: apiKeyWithAuthorizations.APIKey.ID, + Key: apiKeyWithAuthorizations.APIKey.Key, + Name: apiKeyWithAuthorizations.APIKey.Name, + CreatedOn: apiKeyWithAuthorizations.APIKey.CreatedOn, + }, + Authorizations: []*pb.AuthorizationDetails{ + { + AuthorizationType: authorizationDetails.AuthorizationType, + AuthorizationId: authorizationDetails.AuthorizationID, + ResourceType: authorizationDetails.ResourceType, + ResourceId: authorizationDetails.ResourceID, + OrgId: authorizationDetails.OrgID, + }, + }, + } + pbAPIKeysWithAuthorizations = []*pb.APIKeyWithAuthorizations{&pbAPIKeyWithAuthorizations} + public = true + fragmentVisibility = FragmentVisibilityPublic + pbFragmentConfig, _ = protoutils.StructToStructPb(fragmentConfig) + pbFragmentVisibility = fragmentVisibilityToProto(fragmentVisibility) + f = map[string]interface{}{"name": name, "id": fragmentID} + pbF, _ = protoutils.StructToStructPb(f) + fragment = Fragment{ + ID: fragmentID, + Name: name, + Fragment: &f, + OrganizationOwner: organizationOwner, + Public: public, + CreatedOn: &createdOn, + OrganizationName: name, + RobotPartCount: robotPartCount, + OrganizationCount: organizationCount, + OnlyUsedByOwner: onlyUsedByOwner, + Visibility: fragmentVisibility, + LastUpdated: &lastUpdated, + } + pbFragment = pb.Fragment{ + Id: fragment.ID, + Name: fragment.Name, + Fragment: pbF, + OrganizationOwner: fragment.OrganizationOwner, + Public: fragment.Public, + CreatedOn: fragment.CreatedOn, + OrganizationName: fragment.OrganizationName, + RobotPartCount: fragment.RobotPartCount, + OrganizationCount: fragment.OrganizationCount, + OnlyUsedByOwner: fragment.OnlyUsedByOwner, + Visibility: pbFragmentVisibility, + LastUpdated: fragment.LastUpdated, + } + fragmentConfig = map[string]interface{}{"organizationCount": 4} + editedOn = timestamppb.Timestamp{Seconds: 8, Nanos: 278} + fragmentHistoryEntry = FragmentHistoryEntry{ + Fragment: fragmentID, + EditedOn: &editedOn, + Old: &fragment, + EditedBy: &authenticatorInfo, + } + resourceIDs = []string{resourceID, resourceID2} + permissions = []*AuthorizedPermissions{ + { + ResourceType: resourceType, + ResourceID: resourceID, + Permissions: []string{permission}, + }, + } + siteURL = "url" + metadata = registryItemMLTrainingMetadata{ + MlTrainingMetadata: &MLTrainingMetadata{ + Versions: []*MLTrainingVersion{ + { + Version: version, + CreatedOn: &createdOn, + }, + }, + ModelType: modelType, + ModelFramework: modelFramework, + Draft: draft, + }, + } + registryItem = RegistryItem{ + ItemID: itemID, + OrganizationID: organizationID, + PublicNamespace: namespace, + Name: name, + Type: packageType, + Visibility: visibility, + URL: siteURL, + Description: description, + TotalRobotUsage: totalRobotUsage, + TotalExternalRobotUsage: totalExternalRobotUsage, + TotalOrganizationUsage: totalOrganizationUsage, + TotalExternalOrganizationUsage: totalExternalOrganizationUsage, + Metadata: &metadata, + CreatedAt: &createdOn, + UpdatedAt: &lastUpdated, + } + pbVisibility = visibilityToProto(visibility) + pbRegistryItem, _ = registryItemToProto(®istryItem) + searchTerm = "search_term" + model = Model{ + API: api, + Model: modelString, + } + models = []*Model{&model} + pbModels = []*pb.Model{ + { + Api: model.API, + Model: modelString, + }, + } + firstRun = "first_run" + uploadedAt = timestamppb.Timestamp{Seconds: 3, Nanos: 211} + uploads = Uploads{ + Platform: platform, + UploadedAt: &uploadedAt, + } + pbUploads = pb.Uploads{ + Platform: uploads.Platform, + UploadedAt: uploads.UploadedAt, + } + versionHistory = VersionHistory{ + Version: version, + Files: []*Uploads{&uploads}, + Models: models, + Entrypoint: entryPoint, + FirstRun: &firstRun, + } + pbVersionHistory = pb.VersionHistory{ + Version: versionHistory.Version, + Files: []*pb.Uploads{&pbUploads}, + Models: pbModels, + Entrypoint: versionHistory.Entrypoint, + FirstRun: versionHistory.FirstRun, + } + versionHistories = []*VersionHistory{&versionHistory} + pbVersionHistories = []*pb.VersionHistory{&pbVersionHistory} + module = Module{ + ModuleID: moduleID, + Name: name, + Visibility: visibility, + Versions: versionHistories, + URL: siteURL, + Description: description, + Models: models, + TotalRobotUsage: totalRobotUsage, + TotalOrganizationUsage: totalOrganizationUsage, + OrganizationID: organizationID, + Entrypoint: entryPoint, + PublicNamespace: namespace, + FirstRun: &firstRun, + } + pbModule = pb.Module{ + ModuleId: module.ModuleID, + Name: module.Name, + Visibility: pbVisibility, + Versions: pbVersionHistories, + Url: module.URL, + Description: module.Description, + Models: pbModels, + TotalRobotUsage: module.TotalRobotUsage, + TotalOrganizationUsage: module.TotalOrganizationUsage, + OrganizationId: module.OrganizationID, + Entrypoint: module.Entrypoint, + PublicNamespace: module.PublicNamespace, + FirstRun: module.FirstRun, + } + apiKeyAuthorization = APIKeyAuthorization{ + role: authorizationType, + resourceType: resourceType, + resourceID: resourceID, + } + apiKeyAuthorizations = []APIKeyAuthorization{apiKeyAuthorization} + platformTags = []string{"platform", "tags"} + fileInfo = ModuleFileInfo{ + ModuleID: moduleID, + Version: version, + Platform: platform, + PlatformTags: platformTags, + } + file = []byte{1, 9} +) + +func sharedSecretStateToProto(state SharedSecretState) pb.SharedSecret_State { + switch state { + case SharedSecretStateUnspecified: + return pb.SharedSecret_STATE_UNSPECIFIED + case SharedSecretStateEnabled: + return pb.SharedSecret_STATE_ENABLED + case SharedSecretStateDisabled: + return pb.SharedSecret_STATE_DISABLED + } + return pb.SharedSecret_STATE_UNSPECIFIED +} + +func authenticationTypeToProto(authType AuthenticationType) pb.AuthenticationType { + switch authType { + case AuthenticationTypeUnspecified: + return pb.AuthenticationType_AUTHENTICATION_TYPE_UNSPECIFIED + case AuthenticationTypeWebOAuth: + return pb.AuthenticationType_AUTHENTICATION_TYPE_WEB_OAUTH + case AuthenticationTypeAPIKey: + return pb.AuthenticationType_AUTHENTICATION_TYPE_API_KEY + case AuthenticationTypeRobotPartSecret: + return pb.AuthenticationType_AUTHENTICATION_TYPE_ROBOT_PART_SECRET + case AuthenticationTypeLocationSecret: + return pb.AuthenticationType_AUTHENTICATION_TYPE_LOCATION_SECRET + } + return pb.AuthenticationType_AUTHENTICATION_TYPE_UNSPECIFIED +} + +func modelTypeToProto(modelType ModelType) mlTraining.ModelType { + switch modelType { + case ModelTypeUnspecified: + return mlTraining.ModelType_MODEL_TYPE_UNSPECIFIED + case ModelTypeSingleLabelClassification: + return mlTraining.ModelType_MODEL_TYPE_SINGLE_LABEL_CLASSIFICATION + case ModelTypeMultiLabelClassification: + return mlTraining.ModelType_MODEL_TYPE_MULTI_LABEL_CLASSIFICATION + case ModelTypeObjectDetection: + return mlTraining.ModelType_MODEL_TYPE_OBJECT_DETECTION + } + return mlTraining.ModelType_MODEL_TYPE_UNSPECIFIED +} + +func modelFrameworkToProto(framework ModelFramework) mlTraining.ModelFramework { + switch framework { + case ModelFrameworkUnspecified: + return mlTraining.ModelFramework_MODEL_FRAMEWORK_UNSPECIFIED + case ModelFrameworkTFLite: + return mlTraining.ModelFramework_MODEL_FRAMEWORK_TFLITE + case ModelFrameworkTensorFlow: + return mlTraining.ModelFramework_MODEL_FRAMEWORK_TENSORFLOW + case ModelFrameworkPyTorch: + return mlTraining.ModelFramework_MODEL_FRAMEWORK_PYTORCH + case ModelFrameworkONNX: + return mlTraining.ModelFramework_MODEL_FRAMEWORK_ONNX + } + return mlTraining.ModelFramework_MODEL_FRAMEWORK_UNSPECIFIED +} + +func mlTrainingVersionToProto(version *MLTrainingVersion) *pb.MLTrainingVersion { + return &pb.MLTrainingVersion{ + Version: version.Version, + CreatedOn: version.CreatedOn, + } +} + +func mlTrainingMetadataToProto(md MLTrainingMetadata) *pb.MLTrainingMetadata { + var versions []*pb.MLTrainingVersion + for _, version := range md.Versions { + versions = append(versions, mlTrainingVersionToProto(version)) + } + return &pb.MLTrainingMetadata{ + Versions: versions, + ModelType: modelTypeToProto(md.ModelType), + ModelFramework: modelFrameworkToProto(md.ModelFramework), + Draft: md.Draft, + } +} + +func registryItemToProto(item *RegistryItem) (*pb.RegistryItem, error) { + switch metadata := item.Metadata.(type) { + case *registryItemModuleMetadata: + return &pb.RegistryItem{ + ItemId: item.ItemID, + OrganizationId: item.OrganizationID, + PublicNamespace: item.PublicNamespace, + Name: item.Name, + Type: packageTypeToProto(item.Type), + Visibility: visibilityToProto(item.Visibility), + Url: item.URL, + Description: item.Description, + TotalRobotUsage: item.TotalRobotUsage, + TotalExternalRobotUsage: item.TotalExternalRobotUsage, + TotalOrganizationUsage: item.TotalOrganizationUsage, + TotalExternalOrganizationUsage: item.TotalExternalOrganizationUsage, + Metadata: &pb.RegistryItem_ModuleMetadata{ModuleMetadata: &pb.ModuleMetadata{}}, + CreatedAt: item.CreatedAt, + UpdatedAt: item.UpdatedAt, + }, nil + case *registryItemMLModelMetadata: + return &pb.RegistryItem{ + ItemId: item.ItemID, + OrganizationId: item.OrganizationID, + PublicNamespace: item.PublicNamespace, + Name: item.Name, + Type: packageTypeToProto(item.Type), + Visibility: visibilityToProto(item.Visibility), + Url: item.URL, + Description: item.Description, + TotalRobotUsage: item.TotalRobotUsage, + TotalExternalRobotUsage: item.TotalExternalRobotUsage, + TotalOrganizationUsage: item.TotalOrganizationUsage, + TotalExternalOrganizationUsage: item.TotalExternalOrganizationUsage, + Metadata: &pb.RegistryItem_ModuleMetadata{ModuleMetadata: &pb.ModuleMetadata{}}, + CreatedAt: item.CreatedAt, + UpdatedAt: item.UpdatedAt, + }, nil + case *registryItemMLTrainingMetadata: + protoMetadata := mlTrainingMetadataToProto(*metadata.MlTrainingMetadata) + return &pb.RegistryItem{ + ItemId: item.ItemID, + OrganizationId: item.OrganizationID, + PublicNamespace: item.PublicNamespace, + Name: item.Name, + Type: packageTypeToProto(item.Type), + Visibility: visibilityToProto(item.Visibility), + Url: item.URL, + Description: item.Description, + TotalRobotUsage: item.TotalRobotUsage, + TotalExternalRobotUsage: item.TotalExternalRobotUsage, + TotalOrganizationUsage: item.TotalOrganizationUsage, + TotalExternalOrganizationUsage: item.TotalExternalOrganizationUsage, + Metadata: &pb.RegistryItem_MlTrainingMetadata{MlTrainingMetadata: protoMetadata}, + CreatedAt: item.CreatedAt, + UpdatedAt: item.UpdatedAt, + }, nil + default: + return nil, fmt.Errorf("unknown registry item metadata type: %T", item.Metadata) + } +} + +func createAppGrpcClient() *inject.AppServiceClient { + return &inject.AppServiceClient{} +} + +func TestAppClient(t *testing.T) { + grpcClient := createAppGrpcClient() + client := AppClient{client: grpcClient} + + t.Run("GetUserIDByEmail", func(t *testing.T) { + grpcClient.GetUserIDByEmailFunc = func( + ctx context.Context, in *pb.GetUserIDByEmailRequest, opts ...grpc.CallOption, + ) (*pb.GetUserIDByEmailResponse, error) { + test.That(t, in.Email, test.ShouldEqual, email) + return &pb.GetUserIDByEmailResponse{ + UserId: userID, + }, nil + } + resp, err := client.GetUserIDByEmail(context.Background(), email) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldEqual, userID) + }) + + t.Run("CreateOrganization", func(t *testing.T) { + grpcClient.CreateOrganizationFunc = func( + ctx context.Context, in *pb.CreateOrganizationRequest, opts ...grpc.CallOption, + ) (*pb.CreateOrganizationResponse, error) { + test.That(t, in.Name, test.ShouldEqual, name) + return &pb.CreateOrganizationResponse{ + Organization: &pbOrganization, + }, nil + } + resp, err := client.CreateOrganization(context.Background(), name) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &organization) + }) + + t.Run("ListOrganizations", func(t *testing.T) { + expectedOrganizations := []*Organization{&organization} + grpcClient.ListOrganizationsFunc = func( + ctx context.Context, in *pb.ListOrganizationsRequest, opts ...grpc.CallOption, + ) (*pb.ListOrganizationsResponse, error) { + return &pb.ListOrganizationsResponse{ + Organizations: []*pb.Organization{&pbOrganization}, + }, nil + } + resp, err := client.ListOrganizations(context.Background()) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedOrganizations) + }) + + t.Run("GetOrganizationsWithAccessToLocation", func(t *testing.T) { + expectedOrganizationIdentities := []*OrganizationIdentity{&organizationIdentity} + grpcClient.GetOrganizationsWithAccessToLocationFunc = func( + ctx context.Context, in *pb.GetOrganizationsWithAccessToLocationRequest, opts ...grpc.CallOption, + ) (*pb.GetOrganizationsWithAccessToLocationResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + return &pb.GetOrganizationsWithAccessToLocationResponse{ + OrganizationIdentities: []*pb.OrganizationIdentity{ + { + Id: organizationIdentity.ID, + Name: organizationIdentity.Name, + }, + }, + }, nil + } + resp, err := client.GetOrganizationsWithAccessToLocation(context.Background(), locationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedOrganizationIdentities) + }) + + t.Run("ListOrganizationsByUser", func(t *testing.T) { + expectedOrgDetailsList := []*OrgDetails{&orgDetails} + grpcClient.ListOrganizationsByUserFunc = func( + ctx context.Context, in *pb.ListOrganizationsByUserRequest, opts ...grpc.CallOption, + ) (*pb.ListOrganizationsByUserResponse, error) { + test.That(t, in.UserId, test.ShouldEqual, userID) + return &pb.ListOrganizationsByUserResponse{ + Orgs: []*pb.OrgDetails{ + { + OrgId: orgDetails.OrgID, + OrgName: orgDetails.OrgName, + }, + }, + }, nil + } + resp, err := client.ListOrganizationsByUser(context.Background(), userID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedOrgDetailsList) + }) + + t.Run("GetOrganization", func(t *testing.T) { + grpcClient.GetOrganizationFunc = func( + ctx context.Context, in *pb.GetOrganizationRequest, opts ...grpc.CallOption, + ) (*pb.GetOrganizationResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + return &pb.GetOrganizationResponse{ + Organization: &pbOrganization, + }, nil + } + resp, err := client.GetOrganization(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &organization) + }) + + t.Run("GetOrganizationNamespaceAvailability", func(t *testing.T) { + grpcClient.GetOrganizationNamespaceAvailabilityFunc = func( + ctx context.Context, in *pb.GetOrganizationNamespaceAvailabilityRequest, opts ...grpc.CallOption, + ) (*pb.GetOrganizationNamespaceAvailabilityResponse, error) { + test.That(t, in.PublicNamespace, test.ShouldEqual, namespace) + return &pb.GetOrganizationNamespaceAvailabilityResponse{ + Available: available, + }, nil + } + resp, err := client.GetOrganizationNamespaceAvailability(context.Background(), namespace) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldEqual, available) + }) + + t.Run("UpdateOrganization", func(t *testing.T) { + grpcClient.UpdateOrganizationFunc = func( + ctx context.Context, in *pb.UpdateOrganizationRequest, opts ...grpc.CallOption, + ) (*pb.UpdateOrganizationResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + test.That(t, in.Name, test.ShouldEqual, &name) + test.That(t, in.PublicNamespace, test.ShouldEqual, &namespace) + test.That(t, in.Region, test.ShouldEqual, ®ion) + test.That(t, in.Cid, test.ShouldEqual, &cid) + return &pb.UpdateOrganizationResponse{ + Organization: &pbOrganization, + }, nil + } + resp, err := client.UpdateOrganization(context.Background(), organizationID, UpdateOrganizationOptions{ + &name, &namespace, ®ion, &cid, + }) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &organization) + }) + + t.Run("DeleteOrganization", func(t *testing.T) { + grpcClient.DeleteOrganizationFunc = func( + ctx context.Context, in *pb.DeleteOrganizationRequest, opts ...grpc.CallOption, + ) (*pb.DeleteOrganizationResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + return &pb.DeleteOrganizationResponse{}, nil + } + err := client.DeleteOrganization(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ListOrganizationMembers", func(t *testing.T) { + expectedMembers := []*OrganizationMember{&member} + expectedInvites := []*OrganizationInvite{&invite} + grpcClient.ListOrganizationMembersFunc = func( + ctx context.Context, in *pb.ListOrganizationMembersRequest, opts ...grpc.CallOption, + ) (*pb.ListOrganizationMembersResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + return &pb.ListOrganizationMembersResponse{ + Members: []*pb.OrganizationMember{ + { + UserId: member.UserID, + Emails: member.Emails, + DateAdded: member.DateAdded, + LastLogin: member.LastLogin, + }, + }, + Invites: []*pb.OrganizationInvite{&pbInvite}, + }, nil + } + members, invites, err := client.ListOrganizationMembers(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, members, test.ShouldResemble, expectedMembers) + test.That(t, invites, test.ShouldResemble, expectedInvites) + }) + + t.Run("CreateOrganizationInvite", func(t *testing.T) { + grpcClient.CreateOrganizationInviteFunc = func( + ctx context.Context, in *pb.CreateOrganizationInviteRequest, opts ...grpc.CallOption, + ) (*pb.CreateOrganizationInviteResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + test.That(t, in.Email, test.ShouldEqual, email) + test.That(t, in.Authorizations, test.ShouldResemble, pbAuthorizations) + test.That(t, in.SendEmailInvite, test.ShouldEqual, &sendEmailInvite) + return &pb.CreateOrganizationInviteResponse{ + Invite: &pbInvite, + }, nil + } + resp, err := client.CreateOrganizationInvite(context.Background(), organizationID, email, authorizations, CreateOrganizationInviteOptions{ + &sendEmailInvite, + }) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &invite) + }) + + t.Run("UpdateOrganizationInviteAuthorizations", func(t *testing.T) { + grpcClient.UpdateOrganizationInviteAuthorizationsFunc = func( + ctx context.Context, in *pb.UpdateOrganizationInviteAuthorizationsRequest, opts ...grpc.CallOption, + ) (*pb.UpdateOrganizationInviteAuthorizationsResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + return &pb.UpdateOrganizationInviteAuthorizationsResponse{ + Invite: &pbInvite, + }, nil + } + resp, err := client.UpdateOrganizationInviteAuthorizations(context.Background(), organizationID, email, authorizations, authorizations) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &invite) + }) + + t.Run("DeleteOrganizationMember", func(t *testing.T) { + grpcClient.DeleteOrganizationMemberFunc = func( + ctx context.Context, in *pb.DeleteOrganizationMemberRequest, opts ...grpc.CallOption, + ) (*pb.DeleteOrganizationMemberResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + test.That(t, in.UserId, test.ShouldEqual, userID) + return &pb.DeleteOrganizationMemberResponse{}, nil + } + err := client.DeleteOrganizationMember(context.Background(), organizationID, userID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("DeleteOrganizationInvite", func(t *testing.T) { + grpcClient.DeleteOrganizationInviteFunc = func( + ctx context.Context, in *pb.DeleteOrganizationInviteRequest, opts ...grpc.CallOption, + ) (*pb.DeleteOrganizationInviteResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + test.That(t, in.Email, test.ShouldEqual, email) + return &pb.DeleteOrganizationInviteResponse{}, nil + } + err := client.DeleteOrganizationInvite(context.Background(), organizationID, email) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ResendOrganizationInvite", func(t *testing.T) { + grpcClient.ResendOrganizationInviteFunc = func( + ctx context.Context, in *pb.ResendOrganizationInviteRequest, opts ...grpc.CallOption, + ) (*pb.ResendOrganizationInviteResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + test.That(t, in.Email, test.ShouldEqual, email) + return &pb.ResendOrganizationInviteResponse{ + Invite: &pbInvite, + }, nil + } + resp, err := client.ResendOrganizationInvite(context.Background(), organizationID, email) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &invite) + }) + + t.Run("EnableBillingService", func(t *testing.T) { + grpcClient.EnableBillingServiceFunc = func( + ctx context.Context, in *pb.EnableBillingServiceRequest, opts ...grpc.CallOption, + ) (*pb.EnableBillingServiceResponse, error) { + test.That(t, in.OrgId, test.ShouldEqual, organizationID) + test.That(t, in.BillingAddress, test.ShouldResemble, &pbAddress) + return &pb.EnableBillingServiceResponse{}, nil + } + err := client.EnableBillingService(context.Background(), organizationID, &address) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("DisableBillingService", func(t *testing.T) { + grpcClient.DisableBillingServiceFunc = func( + ctx context.Context, in *pb.DisableBillingServiceRequest, opts ...grpc.CallOption, + ) (*pb.DisableBillingServiceResponse, error) { + test.That(t, in.OrgId, test.ShouldEqual, organizationID) + return &pb.DisableBillingServiceResponse{}, nil + } + err := client.DisableBillingService(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("UpdateBillingService", func(t *testing.T) { + grpcClient.UpdateBillingServiceFunc = func( + ctx context.Context, in *pb.UpdateBillingServiceRequest, opts ...grpc.CallOption, + ) (*pb.UpdateBillingServiceResponse, error) { + test.That(t, in.OrgId, test.ShouldEqual, organizationID) + test.That(t, in.BillingAddress, test.ShouldResemble, &pbAddress) + test.That(t, in.BillingSupportEmail, test.ShouldResemble, email) + return &pb.UpdateBillingServiceResponse{}, nil + } + err := client.UpdateBillingService(context.Background(), organizationID, &address, email) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("OrganizationSetSupportEmail", func(t *testing.T) { + grpcClient.OrganizationSetSupportEmailFunc = func( + ctx context.Context, in *pb.OrganizationSetSupportEmailRequest, opts ...grpc.CallOption, + ) (*pb.OrganizationSetSupportEmailResponse, error) { + test.That(t, in.OrgId, test.ShouldEqual, organizationID) + test.That(t, in.Email, test.ShouldResemble, email) + return &pb.OrganizationSetSupportEmailResponse{}, nil + } + err := client.OrganizationSetSupportEmail(context.Background(), organizationID, email) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("OrganizationGetSupportEmail", func(t *testing.T) { + grpcClient.OrganizationGetSupportEmailFunc = func( + ctx context.Context, in *pb.OrganizationGetSupportEmailRequest, opts ...grpc.CallOption, + ) (*pb.OrganizationGetSupportEmailResponse, error) { + test.That(t, in.OrgId, test.ShouldEqual, organizationID) + return &pb.OrganizationGetSupportEmailResponse{ + Email: email, + }, nil + } + resp, err := client.OrganizationGetSupportEmail(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldEqual, email) + }) + + t.Run("CreateLocation", func(t *testing.T) { + grpcClient.CreateLocationFunc = func( + ctx context.Context, in *pb.CreateLocationRequest, opts ...grpc.CallOption, + ) (*pb.CreateLocationResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + test.That(t, in.Name, test.ShouldEqual, name) + test.That(t, in.ParentLocationId, test.ShouldEqual, &parentLocationID) + return &pb.CreateLocationResponse{ + Location: &pbLocation, + }, nil + } + resp, err := client.CreateLocation(context.Background(), organizationID, name, CreateLocationOptions{&parentLocationID}) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &location) + }) + + t.Run("GetLocation", func(t *testing.T) { + grpcClient.GetLocationFunc = func( + ctx context.Context, in *pb.GetLocationRequest, opts ...grpc.CallOption, + ) (*pb.GetLocationResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + return &pb.GetLocationResponse{ + Location: &pbLocation, + }, nil + } + resp, err := client.GetLocation(context.Background(), locationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &location) + }) + + t.Run("UpdateLocation", func(t *testing.T) { + grpcClient.UpdateLocationFunc = func( + ctx context.Context, in *pb.UpdateLocationRequest, opts ...grpc.CallOption, + ) (*pb.UpdateLocationResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + test.That(t, in.Name, test.ShouldEqual, &name) + test.That(t, in.ParentLocationId, test.ShouldEqual, &parentLocationID) + test.That(t, in.Region, test.ShouldEqual, ®ion) + return &pb.UpdateLocationResponse{ + Location: &pbLocation, + }, nil + } + resp, err := client.UpdateLocation(context.Background(), locationID, UpdateLocationOptions{&name, &parentLocationID, ®ion}) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &location) + }) + + t.Run("DeleteLocation", func(t *testing.T) { + grpcClient.DeleteLocationFunc = func( + ctx context.Context, in *pb.DeleteLocationRequest, opts ...grpc.CallOption, + ) (*pb.DeleteLocationResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + return &pb.DeleteLocationResponse{}, nil + } + err := client.DeleteLocation(context.Background(), locationID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ListLocations", func(t *testing.T) { + expectedLocations := []*Location{&location} + grpcClient.ListLocationsFunc = func( + ctx context.Context, in *pb.ListLocationsRequest, opts ...grpc.CallOption, + ) (*pb.ListLocationsResponse, error) { + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + return &pb.ListLocationsResponse{ + Locations: []*pb.Location{&pbLocation}, + }, nil + } + resp, err := client.ListLocations(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedLocations) + }) + + t.Run("ShareLocation", func(t *testing.T) { + grpcClient.ShareLocationFunc = func( + ctx context.Context, in *pb.ShareLocationRequest, opts ...grpc.CallOption, + ) (*pb.ShareLocationResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + return &pb.ShareLocationResponse{}, nil + } + err := client.ShareLocation(context.Background(), locationID, organizationID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("UnshareLocation", func(t *testing.T) { + grpcClient.UnshareLocationFunc = func( + ctx context.Context, in *pb.UnshareLocationRequest, opts ...grpc.CallOption, + ) (*pb.UnshareLocationResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + test.That(t, in.OrganizationId, test.ShouldEqual, organizationID) + return &pb.UnshareLocationResponse{}, nil + } + err := client.UnshareLocation(context.Background(), locationID, organizationID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("LocationAuth", func(t *testing.T) { + grpcClient.LocationAuthFunc = func( + ctx context.Context, in *pb.LocationAuthRequest, opts ...grpc.CallOption, + ) (*pb.LocationAuthResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + return &pb.LocationAuthResponse{ + Auth: &pbLocationAuth, + }, nil + } + resp, err := client.LocationAuth(context.Background(), locationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &locationAuth) + }) + + t.Run("CreateLocationSecret", func(t *testing.T) { + grpcClient.CreateLocationSecretFunc = func( + ctx context.Context, in *pb.CreateLocationSecretRequest, opts ...grpc.CallOption, + ) (*pb.CreateLocationSecretResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + return &pb.CreateLocationSecretResponse{ + Auth: &pbLocationAuth, + }, nil + } + resp, err := client.CreateLocationSecret(context.Background(), locationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &locationAuth) + }) + + t.Run("DeleteLocationSecret", func(t *testing.T) { + grpcClient.DeleteLocationSecretFunc = func( + ctx context.Context, in *pb.DeleteLocationSecretRequest, opts ...grpc.CallOption, + ) (*pb.DeleteLocationSecretResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + test.That(t, in.SecretId, test.ShouldEqual, secretID) + return &pb.DeleteLocationSecretResponse{}, nil + } + err := client.DeleteLocationSecret(context.Background(), locationID, secretID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("GetRobot", func(t *testing.T) { + grpcClient.GetRobotFunc = func( + ctx context.Context, in *pb.GetRobotRequest, opts ...grpc.CallOption, + ) (*pb.GetRobotResponse, error) { + test.That(t, in.Id, test.ShouldEqual, robotID) + return &pb.GetRobotResponse{ + Robot: &pbRobot, + }, nil + } + resp, err := client.GetRobot(context.Background(), robotID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &robot) + }) + + t.Run("GetRoverRentalRobots", func(t *testing.T) { + expectedRobots := []*RoverRentalRobot{&roverRentalRobot} + grpcClient.GetRoverRentalRobotsFunc = func( + ctx context.Context, in *pb.GetRoverRentalRobotsRequest, opts ...grpc.CallOption, + ) (*pb.GetRoverRentalRobotsResponse, error) { + test.That(t, in.OrgId, test.ShouldEqual, organizationID) + return &pb.GetRoverRentalRobotsResponse{ + Robots: []*pb.RoverRentalRobot{ + { + RobotId: roverRentalRobot.RobotID, + LocationId: roverRentalRobot.LocationID, + RobotName: roverRentalRobot.RobotName, + RobotMainPartId: partID, + }, + }, + }, nil + } + resp, err := client.GetRoverRentalRobots(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedRobots) + }) + + t.Run("GetRobotParts", func(t *testing.T) { + expectedRobotParts := []*RobotPart{&robotPart} + grpcClient.GetRobotPartsFunc = func( + ctx context.Context, in *pb.GetRobotPartsRequest, opts ...grpc.CallOption, + ) (*pb.GetRobotPartsResponse, error) { + test.That(t, in.RobotId, test.ShouldEqual, robotID) + return &pb.GetRobotPartsResponse{ + Parts: []*pb.RobotPart{&pbRobotPart}, + }, nil + } + resp, err := client.GetRobotParts(context.Background(), robotID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedRobotParts) + }) + + t.Run("GetRobotPart", func(t *testing.T) { + grpcClient.GetRobotPartFunc = func( + ctx context.Context, in *pb.GetRobotPartRequest, opts ...grpc.CallOption, + ) (*pb.GetRobotPartResponse, error) { + test.That(t, in.Id, test.ShouldEqual, partID) + return &pb.GetRobotPartResponse{ + Part: &pbRobotPart, + ConfigJson: configJSON, + }, nil + } + part, json, err := client.GetRobotPart(context.Background(), partID) + test.That(t, err, test.ShouldBeNil) + test.That(t, json, test.ShouldEqual, configJSON) + test.That(t, part, test.ShouldResemble, &robotPart) + }) + + t.Run("GetRobotPartLogs", func(t *testing.T) { + grpcClient.GetRobotPartLogsFunc = func( + ctx context.Context, in *pb.GetRobotPartLogsRequest, opts ...grpc.CallOption, + ) (*pb.GetRobotPartLogsResponse, error) { + test.That(t, in.Id, test.ShouldEqual, partID) + test.That(t, in.Filter, test.ShouldEqual, &filter) + test.That(t, in.PageToken, test.ShouldEqual, &pageToken) + test.That(t, in.Levels, test.ShouldResemble, levels) + test.That(t, in.Start, test.ShouldEqual, &start) + test.That(t, in.End, test.ShouldEqual, &end) + test.That(t, in.Limit, test.ShouldEqual, &int64Limit) + test.That(t, in.Source, test.ShouldEqual, &source) + return &pb.GetRobotPartLogsResponse{ + Logs: []*common.LogEntry{&pbLogEntry}, + NextPageToken: pageToken, + }, nil + } + logs, token, err := client.GetRobotPartLogs(context.Background(), partID, GetRobotPartLogsOptions{ + &filter, &pageToken, levels, &start, &end, &int64Limit, &source, + }) + test.That(t, err, test.ShouldBeNil) + test.That(t, token, test.ShouldEqual, pageToken) + test.That(t, logs, test.ShouldResemble, logEntries) + }) + + t.Run("TailRobotPartLogs", func(t *testing.T) { + mockStream := &inject.AppServiceTailRobotPartLogsClient{ + RecvFunc: func() (*pb.TailRobotPartLogsResponse, error) { + return &pb.TailRobotPartLogsResponse{ + Logs: []*common.LogEntry{&pbLogEntry}, + }, nil + }, + } + grpcClient.TailRobotPartLogsFunc = func( + ctx context.Context, in *pb.TailRobotPartLogsRequest, opts ...grpc.CallOption, + ) (pb.AppService_TailRobotPartLogsClient, error) { + test.That(t, in.Id, test.ShouldEqual, partID) + test.That(t, in.ErrorsOnly, test.ShouldEqual, errorsOnly) + test.That(t, in.Filter, test.ShouldEqual, &filter) + return mockStream, nil + } + stream, err := client.TailRobotPartLogs(context.Background(), partID, errorsOnly, TailRobotPartLogsOptions{&filter}) + test.That(t, err, test.ShouldBeNil) + resp, err := stream.Next() + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, []*LogEntry{&logEntry}) + }) + + t.Run("GetRobotPartHistory", func(t *testing.T) { + expectedEntries := []*RobotPartHistoryEntry{&robotPartHistoryEntry} + grpcClient.GetRobotPartHistoryFunc = func( + ctx context.Context, in *pb.GetRobotPartHistoryRequest, opts ...grpc.CallOption, + ) (*pb.GetRobotPartHistoryResponse, error) { + test.That(t, in.Id, test.ShouldEqual, partID) + return &pb.GetRobotPartHistoryResponse{ + History: []*pb.RobotPartHistoryEntry{ + { + Part: robotPartHistoryEntry.Part, + Robot: robotPartHistoryEntry.Robot, + When: robotPartHistoryEntry.When, + Old: &pbRobotPart, + EditedBy: &pbAuthenticatorInfo, + }, + }, + }, nil + } + resp, err := client.GetRobotPartHistory(context.Background(), partID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedEntries) + }) + + t.Run("UpdateRobotPart", func(t *testing.T) { + grpcClient.UpdateRobotPartFunc = func( + ctx context.Context, in *pb.UpdateRobotPartRequest, opts ...grpc.CallOption, + ) (*pb.UpdateRobotPartResponse, error) { + test.That(t, in.Id, test.ShouldEqual, partID) + test.That(t, in.Name, test.ShouldEqual, name) + test.That(t, in.RobotConfig, test.ShouldResemble, pbRobotConfig) + return &pb.UpdateRobotPartResponse{ + Part: &pbRobotPart, + }, nil + } + resp, err := client.UpdateRobotPart(context.Background(), partID, name, robotConfig) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &robotPart) + }) + + t.Run("NewRobotPart", func(t *testing.T) { + grpcClient.NewRobotPartFunc = func( + ctx context.Context, in *pb.NewRobotPartRequest, opts ...grpc.CallOption, + ) (*pb.NewRobotPartResponse, error) { + test.That(t, in.RobotId, test.ShouldEqual, robotID) + test.That(t, in.PartName, test.ShouldEqual, name) + return &pb.NewRobotPartResponse{ + PartId: partID, + }, nil + } + resp, err := client.NewRobotPart(context.Background(), robotID, name) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldEqual, partID) + }) + + t.Run("DeleteRobotPart", func(t *testing.T) { + grpcClient.DeleteRobotPartFunc = func( + ctx context.Context, in *pb.DeleteRobotPartRequest, opts ...grpc.CallOption, + ) (*pb.DeleteRobotPartResponse, error) { + test.That(t, in.PartId, test.ShouldEqual, partID) + return &pb.DeleteRobotPartResponse{}, nil + } + err := client.DeleteRobotPart(context.Background(), partID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("GetRobotAPIKeys", func(t *testing.T) { + expectedAPIKeyWithAuthorizations := []*APIKeyWithAuthorizations{&apiKeyWithAuthorizations} + grpcClient.GetRobotAPIKeysFunc = func( + ctx context.Context, in *pb.GetRobotAPIKeysRequest, opts ...grpc.CallOption, + ) (*pb.GetRobotAPIKeysResponse, error) { + test.That(t, in.RobotId, test.ShouldEqual, robotID) + return &pb.GetRobotAPIKeysResponse{ + ApiKeys: pbAPIKeysWithAuthorizations, + }, nil + } + resp, err := client.GetRobotAPIKeys(context.Background(), robotID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedAPIKeyWithAuthorizations) + }) + + t.Run("MarkPartForRestart", func(t *testing.T) { + grpcClient.MarkPartForRestartFunc = func( + ctx context.Context, in *pb.MarkPartForRestartRequest, opts ...grpc.CallOption, + ) (*pb.MarkPartForRestartResponse, error) { + test.That(t, in.PartId, test.ShouldEqual, partID) + return &pb.MarkPartForRestartResponse{}, nil + } + err := client.MarkPartForRestart(context.Background(), partID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("CreateRobotPartSecret", func(t *testing.T) { + grpcClient.CreateRobotPartSecretFunc = func( + ctx context.Context, in *pb.CreateRobotPartSecretRequest, opts ...grpc.CallOption, + ) (*pb.CreateRobotPartSecretResponse, error) { + test.That(t, in.PartId, test.ShouldEqual, partID) + return &pb.CreateRobotPartSecretResponse{ + Part: &pbRobotPart, + }, nil + } + resp, err := client.CreateRobotPartSecret(context.Background(), partID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &robotPart) + }) + + t.Run("DeleteRobotPartSecret", func(t *testing.T) { + grpcClient.DeleteRobotPartSecretFunc = func( + ctx context.Context, in *pb.DeleteRobotPartSecretRequest, opts ...grpc.CallOption, + ) (*pb.DeleteRobotPartSecretResponse, error) { + test.That(t, in.PartId, test.ShouldEqual, partID) + test.That(t, in.SecretId, test.ShouldEqual, secretID) + return &pb.DeleteRobotPartSecretResponse{}, nil + } + err := client.DeleteRobotPartSecret(context.Background(), partID, secretID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ListRobots", func(t *testing.T) { + expectedRobots := []*Robot{&robot} + grpcClient.ListRobotsFunc = func( + ctx context.Context, in *pb.ListRobotsRequest, opts ...grpc.CallOption, + ) (*pb.ListRobotsResponse, error) { + test.That(t, in.LocationId, test.ShouldEqual, locationID) + return &pb.ListRobotsResponse{ + Robots: []*pb.Robot{&pbRobot}, + }, nil + } + resp, err := client.ListRobots(context.Background(), locationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedRobots) + }) + + t.Run("NewRobot", func(t *testing.T) { + grpcClient.NewRobotFunc = func( + ctx context.Context, in *pb.NewRobotRequest, opts ...grpc.CallOption, + ) (*pb.NewRobotResponse, error) { + test.That(t, in.Name, test.ShouldEqual, name) + test.That(t, in.Location, test.ShouldEqual, locationID) + return &pb.NewRobotResponse{ + Id: robotID, + }, nil + } + resp, err := client.NewRobot(context.Background(), name, locationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldEqual, robotID) + }) + + t.Run("UpdateRobot", func(t *testing.T) { + grpcClient.UpdateRobotFunc = func( + ctx context.Context, in *pb.UpdateRobotRequest, opts ...grpc.CallOption, + ) (*pb.UpdateRobotResponse, error) { + test.That(t, in.Id, test.ShouldEqual, robotID) + test.That(t, in.Name, test.ShouldEqual, name) + test.That(t, in.Location, test.ShouldEqual, locationID) + return &pb.UpdateRobotResponse{ + Robot: &pbRobot, + }, nil + } + resp, err := client.UpdateRobot(context.Background(), robotID, name, locationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &robot) + }) + + t.Run("DeleteRobot", func(t *testing.T) { + grpcClient.DeleteRobotFunc = func( + ctx context.Context, in *pb.DeleteRobotRequest, opts ...grpc.CallOption, + ) (*pb.DeleteRobotResponse, error) { + test.That(t, in.Id, test.ShouldEqual, robotID) + return &pb.DeleteRobotResponse{}, nil + } + err := client.DeleteRobot(context.Background(), robotID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("GetFragment", func(t *testing.T) { + grpcClient.GetFragmentFunc = func( + ctx context.Context, in *pb.GetFragmentRequest, opts ...grpc.CallOption, + ) (*pb.GetFragmentResponse, error) { + test.That(t, in.Id, test.ShouldEqual, fragmentID) + return &pb.GetFragmentResponse{ + Fragment: &pbFragment, + }, nil + } + resp, err := client.GetFragment(context.Background(), fragmentID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &fragment) + }) + + t.Run("CreateFragment", func(t *testing.T) { + grpcClient.CreateFragmentFunc = func( + ctx context.Context, in *pb.CreateFragmentRequest, opts ...grpc.CallOption, + ) (*pb.CreateFragmentResponse, error) { + test.That(t, in.Name, test.ShouldEqual, name) + test.That(t, in.Config, test.ShouldResemble, pbFragmentConfig) + test.That(t, in.Visibility, test.ShouldResemble, &pbFragmentVisibility) + return &pb.CreateFragmentResponse{ + Fragment: &pbFragment, + }, nil + } + resp, err := client.CreateFragment(context.Background(), organizationID, name, fragmentConfig, CreateFragmentOptions{&fragmentVisibility}) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &fragment) + }) + + t.Run("UpdateFragment", func(t *testing.T) { + grpcClient.UpdateFragmentFunc = func( + ctx context.Context, in *pb.UpdateFragmentRequest, opts ...grpc.CallOption, + ) (*pb.UpdateFragmentResponse, error) { + test.That(t, in.Id, test.ShouldEqual, fragmentID) + test.That(t, in.Name, test.ShouldEqual, name) + test.That(t, in.Config, test.ShouldResemble, pbFragmentConfig) + test.That(t, in.Public, test.ShouldEqual, &public) + test.That(t, in.Visibility, test.ShouldResemble, &pbFragmentVisibility) + return &pb.UpdateFragmentResponse{ + Fragment: &pbFragment, + }, nil + } + resp, err := client.UpdateFragment( + context.Background(), fragmentID, name, fragmentConfig, UpdateFragmentOptions{&public, &fragmentVisibility}, + ) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &fragment) + }) + + t.Run("DeleteFragment", func(t *testing.T) { + grpcClient.DeleteFragmentFunc = func( + ctx context.Context, in *pb.DeleteFragmentRequest, opts ...grpc.CallOption, + ) (*pb.DeleteFragmentResponse, error) { + test.That(t, in.Id, test.ShouldEqual, fragmentID) + return &pb.DeleteFragmentResponse{}, nil + } + err := client.DeleteFragment(context.Background(), fragmentID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ListMachineFragments", func(t *testing.T) { + expectedFragments := []*Fragment{&fragment} + additionalFragmentIDs := []string{fragmentID} + grpcClient.ListMachineFragmentsFunc = func( + ctx context.Context, in *pb.ListMachineFragmentsRequest, opts ...grpc.CallOption, + ) (*pb.ListMachineFragmentsResponse, error) { + test.That(t, in.MachineId, test.ShouldEqual, robotID) + test.That(t, in.AdditionalFragmentIds, test.ShouldResemble, additionalFragmentIDs) + return &pb.ListMachineFragmentsResponse{ + Fragments: []*pb.Fragment{&pbFragment}, + }, nil + } + resp, err := client.ListMachineFragments(context.Background(), robotID, ListMachineFragmentsOptions{additionalFragmentIDs}) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedFragments) + }) + + t.Run("GetFragmentHistory", func(t *testing.T) { + expectedHistory := []*FragmentHistoryEntry{&fragmentHistoryEntry} + grpcClient.GetFragmentHistoryFunc = func( + ctx context.Context, in *pb.GetFragmentHistoryRequest, opts ...grpc.CallOption, + ) (*pb.GetFragmentHistoryResponse, error) { + test.That(t, in.Id, test.ShouldEqual, fragmentID) + test.That(t, in.PageToken, test.ShouldResemble, &pageToken) + test.That(t, in.PageLimit, test.ShouldResemble, &int64Limit) + return &pb.GetFragmentHistoryResponse{ + History: []*pb.FragmentHistoryEntry{ + { + Fragment: fragmentHistoryEntry.Fragment, + EditedOn: fragmentHistoryEntry.EditedOn, + Old: &pbFragment, + EditedBy: &pbAuthenticatorInfo, + }, + }, + NextPageToken: pageToken, + }, nil + } + resp, token, err := client.GetFragmentHistory(context.Background(), fragmentID, GetFragmentHistoryOptions{&pageToken, &int64Limit}) + test.That(t, err, test.ShouldBeNil) + test.That(t, token, test.ShouldEqual, pageToken) + test.That(t, resp, test.ShouldResemble, expectedHistory) + }) + + t.Run("createAuthorization", func(t *testing.T) { + resp, err := createAuthorization(authorization.OrganizationID, + authorization.IdentityID, + authorization.IdentityType, + authorization.AuthorizationType, + authorization.ResourceType, + authorization.ResourceID, + ) + test.That(t, resp, test.ShouldResemble, &pbAuthorization) + test.That(t, err, test.ShouldBeNil) + resp, err = createAuthorization( + authorization.OrganizationID, + authorization.IdentityID, + authorization.IdentityType, + badAuthorizationType, + authorization.ResourceType, + authorization.ResourceID, + ) + test.That(t, resp, test.ShouldBeNil) + test.That(t, err.Error(), test.ShouldEqual, "role string must be 'owner' or 'operator'") + resp, err = createAuthorization( + authorization.OrganizationID, + authorization.IdentityID, + authorization.IdentityType, + authorization.AuthorizationType, + badResourceType, + authorization.ResourceID, + ) + test.That(t, resp, test.ShouldBeNil) + test.That(t, err.Error(), test.ShouldEqual, "resourceType must be 'organization', 'location', or 'robot'") + }) + + t.Run("AddRole", func(t *testing.T) { + grpcClient.AddRoleFunc = func( + ctx context.Context, in *pb.AddRoleRequest, opts ...grpc.CallOption, + ) (*pb.AddRoleResponse, error) { + test.That(t, in.Authorization, test.ShouldResemble, &pbAuthorization) + return &pb.AddRoleResponse{}, nil + } + err := client.AddRole( + context.Background(), + authorization.OrganizationID, + authorization.IdentityID, + authorization.AuthorizationType, + authorization.ResourceType, + authorization.ResourceID, + ) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("RemoveRole", func(t *testing.T) { + grpcClient.RemoveRoleFunc = func( + ctx context.Context, in *pb.RemoveRoleRequest, opts ...grpc.CallOption, + ) (*pb.RemoveRoleResponse, error) { + test.That(t, in.Authorization, test.ShouldResemble, &pbAuthorization) + return &pb.RemoveRoleResponse{}, nil + } + err := client.RemoveRole(context.Background(), &authorization) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ChangeRole", func(t *testing.T) { + grpcClient.ChangeRoleFunc = func( + ctx context.Context, in *pb.ChangeRoleRequest, opts ...grpc.CallOption, + ) (*pb.ChangeRoleResponse, error) { + test.That(t, in.OldAuthorization, test.ShouldResemble, &pbAuthorization) + test.That(t, in.NewAuthorization, test.ShouldResemble, &pbAuthorization2) + return &pb.ChangeRoleResponse{}, nil + } + err := client.ChangeRole( + context.Background(), + &authorization, + authorization2.OrganizationID, + authorization2.IdentityID, + authorization2.AuthorizationType, + authorization2.ResourceType, + authorization2.ResourceID, + ) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ListAuthorizations", func(t *testing.T) { + grpcClient.ListAuthorizationsFunc = func( + ctx context.Context, in *pb.ListAuthorizationsRequest, opts ...grpc.CallOption, + ) (*pb.ListAuthorizationsResponse, error) { + test.That(t, in.OrganizationId, test.ShouldResemble, organizationID) + test.That(t, in.ResourceIds, test.ShouldResemble, resourceIDs) + return &pb.ListAuthorizationsResponse{ + Authorizations: pbAuthorizations, + }, nil + } + resp, err := client.ListAuthorizations(context.Background(), organizationID, ListAuthorizationsOptions{resourceIDs}) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, authorizations) + }) + + t.Run("CheckPermissions", func(t *testing.T) { + pbPermissions := []*pb.AuthorizedPermissions{ + { + ResourceType: permissions[0].ResourceType, + ResourceId: permissions[0].ResourceID, + Permissions: permissions[0].Permissions, + }, + } + grpcClient.CheckPermissionsFunc = func( + ctx context.Context, in *pb.CheckPermissionsRequest, opts ...grpc.CallOption, + ) (*pb.CheckPermissionsResponse, error) { + test.That(t, in.Permissions, test.ShouldResemble, pbPermissions) + return &pb.CheckPermissionsResponse{ + AuthorizedPermissions: pbPermissions, + }, nil + } + resp, err := client.CheckPermissions(context.Background(), permissions) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, permissions) + }) + + t.Run("GetRegistryItem", func(t *testing.T) { + grpcClient.GetRegistryItemFunc = func( + ctx context.Context, in *pb.GetRegistryItemRequest, opts ...grpc.CallOption, + ) (*pb.GetRegistryItemResponse, error) { + test.That(t, in.ItemId, test.ShouldResemble, itemID) + return &pb.GetRegistryItemResponse{ + Item: pbRegistryItem, + }, nil + } + resp, err := client.GetRegistryItem(context.Background(), itemID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, ®istryItem) + }) + + t.Run("CreateRegistryItem", func(t *testing.T) { + grpcClient.CreateRegistryItemFunc = func( + ctx context.Context, in *pb.CreateRegistryItemRequest, opts ...grpc.CallOption, + ) (*pb.CreateRegistryItemResponse, error) { + test.That(t, in.OrganizationId, test.ShouldResemble, registryItem.OrganizationID) + test.That(t, in.Name, test.ShouldResemble, registryItem.Name) + test.That(t, in.Type, test.ShouldResemble, pbRegistryItem.Type) + return &pb.CreateRegistryItemResponse{}, nil + } + err := client.CreateRegistryItem(context.Background(), registryItem.OrganizationID, registryItem.Name, registryItem.Type) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("UpdateRegistryItem", func(t *testing.T) { + grpcClient.UpdateRegistryItemFunc = func( + ctx context.Context, in *pb.UpdateRegistryItemRequest, opts ...grpc.CallOption, + ) (*pb.UpdateRegistryItemResponse, error) { + test.That(t, in.ItemId, test.ShouldResemble, itemID) + test.That(t, in.Type, test.ShouldResemble, packageTypeToProto(packageType)) + test.That(t, in.Description, test.ShouldResemble, description) + test.That(t, in.Visibility, test.ShouldResemble, pbVisibility) + test.That(t, in.Url, test.ShouldResemble, &siteURL) + return &pb.UpdateRegistryItemResponse{}, nil + } + err := client.UpdateRegistryItem( + context.Background(), registryItem.ItemID, packageType, description, visibility, UpdateRegistryItemOptions{&siteURL}, + ) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ListRegistryItems", func(t *testing.T) { + platforms := []string{platform} + namespaces := []string{namespace} + expectedRegistryItems := []*RegistryItem{®istryItem} + grpcClient.ListRegistryItemsFunc = func( + ctx context.Context, in *pb.ListRegistryItemsRequest, opts ...grpc.CallOption, + ) (*pb.ListRegistryItemsResponse, error) { + test.That(t, in.OrganizationId, test.ShouldResemble, &organizationID) + test.That(t, in.Types, test.ShouldResemble, []packages.PackageType{packageTypeToProto(packageType)}) + test.That(t, in.Visibilities, test.ShouldResemble, []pb.Visibility{pbVisibility}) + test.That(t, in.Platforms, test.ShouldResemble, platforms) + test.That(t, in.Statuses, test.ShouldResemble, []pb.RegistryItemStatus{pb.RegistryItemStatus(registryItemStatus)}) + test.That(t, in.SearchTerm, test.ShouldResemble, &searchTerm) + test.That(t, in.PageToken, test.ShouldResemble, &pageToken) + test.That(t, in.PublicNamespaces, test.ShouldResemble, namespaces) + return &pb.ListRegistryItemsResponse{ + Items: []*pb.RegistryItem{pbRegistryItem}, + }, nil + } + resp, err := client.ListRegistryItems(context.Background(), &organizationID, ListRegistryItemsOptions{ + []PackageType{packageType}, + []Visibility{visibility}, + platforms, + []RegistryItemStatus{registryItemStatus}, + &searchTerm, + &pageToken, + namespaces, + }) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedRegistryItems) + }) + + t.Run("DeleteRegistryItem", func(t *testing.T) { + grpcClient.DeleteRegistryItemFunc = func( + ctx context.Context, in *pb.DeleteRegistryItemRequest, opts ...grpc.CallOption, + ) (*pb.DeleteRegistryItemResponse, error) { + test.That(t, in.ItemId, test.ShouldResemble, itemID) + return &pb.DeleteRegistryItemResponse{}, nil + } + err := client.DeleteRegistryItem(context.Background(), registryItem.ItemID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("TransferRegistryItem", func(t *testing.T) { + grpcClient.TransferRegistryItemFunc = func( + ctx context.Context, in *pb.TransferRegistryItemRequest, opts ...grpc.CallOption, + ) (*pb.TransferRegistryItemResponse, error) { + test.That(t, in.ItemId, test.ShouldResemble, itemID) + test.That(t, in.NewPublicNamespace, test.ShouldResemble, namespace) + return &pb.TransferRegistryItemResponse{}, nil + } + err := client.TransferRegistryItem(context.Background(), registryItem.ItemID, namespace) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("UpdateModule", func(t *testing.T) { + grpcClient.UpdateModuleFunc = func( + ctx context.Context, in *pb.UpdateModuleRequest, opts ...grpc.CallOption, + ) (*pb.UpdateModuleResponse, error) { + test.That(t, in.ModuleId, test.ShouldResemble, moduleID) + test.That(t, in.Visibility, test.ShouldResemble, pbVisibility) + test.That(t, in.Url, test.ShouldResemble, siteURL) + test.That(t, in.Description, test.ShouldResemble, description) + test.That(t, in.Models, test.ShouldResemble, pbModels) + test.That(t, in.Entrypoint, test.ShouldResemble, entryPoint) + test.That(t, in.FirstRun, test.ShouldResemble, &firstRun) + return &pb.UpdateModuleResponse{ + Url: siteURL, + }, nil + } + resp, err := client.UpdateModule( + context.Background(), moduleID, visibility, siteURL, description, models, entryPoint, UpdateModuleOptions{&firstRun}, + ) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldEqual, siteURL) + }) + + t.Run("UploadModuleFile", func(t *testing.T) { + mockStream := &inject.AppServiceUploadModuleFileClient{ + SendFunc: func(req *pb.UploadModuleFileRequest) error { + switch moduleFile := req.ModuleFile.(type) { + case *pb.UploadModuleFileRequest_ModuleFileInfo: + test.That(t, moduleFile.ModuleFileInfo, test.ShouldResemble, moduleFileInfoToProto(&fileInfo)) + case *pb.UploadModuleFileRequest_File: + test.That(t, moduleFile.File, test.ShouldResemble, file) + default: + t.Error("unexpected module file type") + } + return nil + }, + CloseAndRecvFunc: func() (*pb.UploadModuleFileResponse, error) { + return &pb.UploadModuleFileResponse{ + Url: siteURL, + }, nil + }, + } + grpcClient.UploadModuleFileFunc = func(ctx context.Context, opts ...grpc.CallOption) (pb.AppService_UploadModuleFileClient, error) { + return mockStream, nil + } + resp, err := client.UploadModuleFile(context.Background(), fileInfo, file) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldEqual, siteURL) + }) + + t.Run("GetModule", func(t *testing.T) { + grpcClient.GetModuleFunc = func( + ctx context.Context, in *pb.GetModuleRequest, opts ...grpc.CallOption, + ) (*pb.GetModuleResponse, error) { + test.That(t, in.ModuleId, test.ShouldResemble, moduleID) + return &pb.GetModuleResponse{ + Module: &pbModule, + }, nil + } + resp, err := client.GetModule(context.Background(), moduleID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, &module) + }) + + t.Run("ListModules", func(t *testing.T) { + expectedModules := []*Module{&module} + grpcClient.ListModulesFunc = func( + ctx context.Context, in *pb.ListModulesRequest, opts ...grpc.CallOption, + ) (*pb.ListModulesResponse, error) { + test.That(t, in.OrganizationId, test.ShouldResemble, &organizationID) + return &pb.ListModulesResponse{ + Modules: []*pb.Module{&pbModule}, + }, nil + } + resp, err := client.ListModules(context.Background(), ListModulesOptions{&organizationID}) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedModules) + }) + + t.Run("CreateKey", func(t *testing.T) { + pbAPIKeyAuthorizations := []*pb.Authorization{ + { + AuthorizationType: apiKeyAuthorization.role, + AuthorizationId: fmt.Sprintf("%s_%s", apiKeyAuthorization.resourceType, apiKeyAuthorization.role), + ResourceType: apiKeyAuthorization.resourceType, + ResourceId: apiKeyAuthorization.resourceID, + IdentityId: "", + OrganizationId: organizationID, + IdentityType: "api-key", + }, + } + grpcClient.CreateKeyFunc = func( + ctx context.Context, in *pb.CreateKeyRequest, opts ...grpc.CallOption, + ) (*pb.CreateKeyResponse, error) { + test.That(t, in.Authorizations, test.ShouldResemble, pbAPIKeyAuthorizations) + test.That(t, in.Name, test.ShouldResemble, name) + return &pb.CreateKeyResponse{ + Key: key, + Id: keyID, + }, nil + } + key, id, err := client.CreateKey(context.Background(), organizationID, apiKeyAuthorizations, name) + test.That(t, err, test.ShouldBeNil) + test.That(t, key, test.ShouldResemble, key) + test.That(t, id, test.ShouldResemble, keyID) + }) + + t.Run("DeleteKey", func(t *testing.T) { + grpcClient.DeleteKeyFunc = func( + ctx context.Context, in *pb.DeleteKeyRequest, opts ...grpc.CallOption, + ) (*pb.DeleteKeyResponse, error) { + test.That(t, in.Id, test.ShouldResemble, keyID) + return &pb.DeleteKeyResponse{}, nil + } + err := client.DeleteKey(context.Background(), keyID) + test.That(t, err, test.ShouldBeNil) + }) + + t.Run("ListKeys", func(t *testing.T) { + expectedAPIKeyWithAuthorizations := []*APIKeyWithAuthorizations{&apiKeyWithAuthorizations} + grpcClient.ListKeysFunc = func( + ctx context.Context, in *pb.ListKeysRequest, opts ...grpc.CallOption, + ) (*pb.ListKeysResponse, error) { + test.That(t, in.OrgId, test.ShouldResemble, organizationID) + return &pb.ListKeysResponse{ + ApiKeys: pbAPIKeysWithAuthorizations, + }, nil + } + resp, err := client.ListKeys(context.Background(), organizationID) + test.That(t, err, test.ShouldBeNil) + test.That(t, resp, test.ShouldResemble, expectedAPIKeyWithAuthorizations) + }) + + t.Run("RenameKey", func(t *testing.T) { + grpcClient.RenameKeyFunc = func( + ctx context.Context, in *pb.RenameKeyRequest, opts ...grpc.CallOption, + ) (*pb.RenameKeyResponse, error) { + test.That(t, in.Id, test.ShouldResemble, keyID) + test.That(t, in.Name, test.ShouldResemble, name) + return &pb.RenameKeyResponse{ + Id: keyID, + Name: name, + }, nil + } + id, name, err := client.RenameKey(context.Background(), keyID, name) + test.That(t, err, test.ShouldBeNil) + test.That(t, id, test.ShouldResemble, keyID) + test.That(t, name, test.ShouldEqual, name) + }) + + t.Run("RotateKey", func(t *testing.T) { + grpcClient.RotateKeyFunc = func( + ctx context.Context, in *pb.RotateKeyRequest, opts ...grpc.CallOption, + ) (*pb.RotateKeyResponse, error) { + test.That(t, in.Id, test.ShouldResemble, keyID) + return &pb.RotateKeyResponse{ + Id: keyID, + Key: key, + }, nil + } + id, key, err := client.RotateKey(context.Background(), keyID) + test.That(t, err, test.ShouldBeNil) + test.That(t, id, test.ShouldResemble, keyID) + test.That(t, key, test.ShouldEqual, key) + }) + + t.Run("CreateKeyFromExistingKeyAuthorizations", func(t *testing.T) { + grpcClient.CreateKeyFromExistingKeyAuthorizationsFunc = func( + ctx context.Context, in *pb.CreateKeyFromExistingKeyAuthorizationsRequest, opts ...grpc.CallOption, + ) (*pb.CreateKeyFromExistingKeyAuthorizationsResponse, error) { + test.That(t, in.Id, test.ShouldResemble, keyID) + return &pb.CreateKeyFromExistingKeyAuthorizationsResponse{ + Id: keyID, + Key: key, + }, nil + } + id, key, err := client.CreateKeyFromExistingKeyAuthorizations(context.Background(), keyID) + test.That(t, err, test.ShouldBeNil) + test.That(t, id, test.ShouldResemble, keyID) + test.That(t, key, test.ShouldEqual, key) + }) +} diff --git a/app/app_proto_conversions.go b/app/app_proto_conversions.go new file mode 100644 index 00000000000..8ebe94202e3 --- /dev/null +++ b/app/app_proto_conversions.go @@ -0,0 +1,630 @@ +package app + +import ( + "errors" + "fmt" + + pb "go.viam.com/api/app/v1" + common "go.viam.com/api/common/v1" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// Organization holds the information of an organization. +type Organization struct { + ID string + Name string + CreatedOn *timestamppb.Timestamp + PublicNamespace string + DefaultRegion string + Cid *string +} + +func organizationFromProto(organization *pb.Organization) *Organization { + return &Organization{ + ID: organization.Id, + Name: organization.Name, + CreatedOn: organization.CreatedOn, + PublicNamespace: organization.PublicNamespace, + DefaultRegion: organization.DefaultRegion, + Cid: organization.Cid, + } +} + +// OrganizationIdentity is used to render an organization's information on the frontend. +type OrganizationIdentity struct { + ID string + Name string +} + +func organizationIdentityFromProto(organizationIdentity *pb.OrganizationIdentity) *OrganizationIdentity { + return &OrganizationIdentity{ + ID: organizationIdentity.Id, + Name: organizationIdentity.Name, + } +} + +// OrgDetails holds the ID and name of the organization. +type OrgDetails struct { + OrgID string + OrgName string +} + +func orgDetailsFromProto(orgDetails *pb.OrgDetails) *OrgDetails { + return &OrgDetails{ + OrgID: orgDetails.OrgId, + OrgName: orgDetails.OrgName, + } +} + +// OrganizationMember holds the information of a member of an organization. +type OrganizationMember struct { + UserID string + Emails []string + DateAdded *timestamppb.Timestamp + LastLogin *timestamppb.Timestamp +} + +func organizationMemberFromProto(organizationMemOrganizationMember *pb.OrganizationMember) *OrganizationMember { + return &OrganizationMember{ + UserID: organizationMemOrganizationMember.UserId, + Emails: organizationMemOrganizationMember.Emails, + DateAdded: organizationMemOrganizationMember.DateAdded, + LastLogin: organizationMemOrganizationMember.LastLogin, + } +} + +// OrganizationInvite is the invite to an organization. +type OrganizationInvite struct { + OrganizationID string + Email string + CreatedOn *timestamppb.Timestamp + Authorizations []*Authorization +} + +func organizationInviteFromProto(organizationInvite *pb.OrganizationInvite) *OrganizationInvite { + var authorizations []*Authorization + for _, authorization := range organizationInvite.Authorizations { + authorizations = append(authorizations, authorizationFromProto(authorization)) + } + return &OrganizationInvite{ + OrganizationID: organizationInvite.OrganizationId, + Email: organizationInvite.Email, + CreatedOn: organizationInvite.CreatedOn, + Authorizations: authorizations, + } +} + +// BillingAddress contains billing address details. +type BillingAddress struct { + AddressLine1 string + AddressLine2 *string + City string + State string +} + +func billingAddressToProto(addr *BillingAddress) *pb.BillingAddress { + return &pb.BillingAddress{ + AddressLine_1: addr.AddressLine1, + AddressLine_2: addr.AddressLine2, + City: addr.City, + State: addr.State, + } +} + +// Location holds the information of a specific location. +type Location struct { + ID string + Name string + ParentLocationID string + Auth *LocationAuth + Organizations []*LocationOrganization + CreatedOn *timestamppb.Timestamp + RobotCount int32 + Config *StorageConfig +} + +func locationFromProto(location *pb.Location) *Location { + var organizations []*LocationOrganization + for _, organization := range location.Organizations { + organizations = append(organizations, locationOrganizationFromProto(organization)) + } + return &Location{ + ID: location.Id, + Name: location.Name, + ParentLocationID: location.ParentLocationId, + Auth: locationAuthFromProto(location.Auth), + Organizations: organizations, + CreatedOn: location.CreatedOn, + RobotCount: location.RobotCount, + Config: storageConfigFromProto(location.Config), + } +} + +// LocationOrganization holds information of an organization the location is shared with. +type LocationOrganization struct { + OrganizationID string + Primary bool +} + +func locationOrganizationFromProto(locationOrganization *pb.LocationOrganization) *LocationOrganization { + return &LocationOrganization{ + OrganizationID: locationOrganization.OrganizationId, + Primary: locationOrganization.Primary, + } +} + +// StorageConfig holds the GCS region that data is stored in. +type StorageConfig struct { + Region string +} + +func storageConfigFromProto(config *pb.StorageConfig) *StorageConfig { + return &StorageConfig{Region: config.Region} +} + +// LocationAuth holds the secrets used to authenticate to a location. +type LocationAuth struct { + LocationID string + Secrets []*SharedSecret +} + +func locationAuthFromProto(locationAuth *pb.LocationAuth) *LocationAuth { + var secrets []*SharedSecret + for _, secret := range locationAuth.Secrets { + secrets = append(secrets, sharedSecretFromProto(secret)) + } + return &LocationAuth{ + LocationID: locationAuth.LocationId, + Secrets: secrets, + } +} + +// Robot holds the information of a machine. +type Robot struct { + ID string + Name string + Location string + LastAccess *timestamppb.Timestamp + CreatedOn *timestamppb.Timestamp +} + +func robotFromProto(robot *pb.Robot) *Robot { + return &Robot{ + ID: robot.Id, + Name: robot.Name, + Location: robot.Location, + LastAccess: robot.LastAccess, + CreatedOn: robot.CreatedOn, + } +} + +// RoverRentalRobot holds the information of a rover rental robot. +type RoverRentalRobot struct { + RobotID string + LocationID string + RobotName string + RobotMainPartID string +} + +func roverRentalRobotFromProto(rrRobot *pb.RoverRentalRobot) *RoverRentalRobot { + return &RoverRentalRobot{ + RobotID: rrRobot.RobotId, + LocationID: rrRobot.LocationId, + RobotName: rrRobot.RobotName, + RobotMainPartID: rrRobot.RobotMainPartId, + } +} + +// RobotPart is a specific machine part. +type RobotPart struct { + ID string + Name string + DNSName string + Secret string + Robot string + LocationID string + RobotConfig *map[string]interface{} + LastAccess *timestamppb.Timestamp + UserSuppliedInfo *map[string]interface{} + MainPart bool + FQDN string + LocalFQDN string + CreatedOn *timestamppb.Timestamp + Secrets []*SharedSecret + LastUpdated *timestamppb.Timestamp +} + +func robotPartFromProto(robotPart *pb.RobotPart) *RobotPart { + var secrets []*SharedSecret + for _, secret := range robotPart.Secrets { + secrets = append(secrets, sharedSecretFromProto(secret)) + } + cfg := robotPart.RobotConfig.AsMap() + info := robotPart.UserSuppliedInfo.AsMap() + return &RobotPart{ + ID: robotPart.Id, + Name: robotPart.Name, + DNSName: robotPart.DnsName, + Secret: robotPart.Secret, + Robot: robotPart.Robot, + LocationID: robotPart.LocationId, + RobotConfig: &cfg, + LastAccess: robotPart.LastAccess, + UserSuppliedInfo: &info, + MainPart: robotPart.MainPart, + FQDN: robotPart.Fqdn, + LocalFQDN: robotPart.LocalFqdn, + CreatedOn: robotPart.CreatedOn, + Secrets: secrets, + LastUpdated: robotPart.LastUpdated, + } +} + +// RobotPartHistoryEntry is a history entry of a robot part. +type RobotPartHistoryEntry struct { + Part string + Robot string + When *timestamppb.Timestamp + Old *RobotPart + EditedBy *AuthenticatorInfo +} + +func robotPartHistoryEntryFromProto(entry *pb.RobotPartHistoryEntry) *RobotPartHistoryEntry { + return &RobotPartHistoryEntry{ + Part: entry.Part, + Robot: entry.Robot, + When: entry.When, + Old: robotPartFromProto(entry.Old), + EditedBy: authenticatorInfoFromProto(entry.EditedBy), + } +} + +// LogEntry holds the information of a single log entry. +type LogEntry struct { + Host string + Level string + Time *timestamppb.Timestamp + LoggerName string + Message string + Caller *map[string]interface{} + Stack string + Fields []*map[string]interface{} +} + +func logEntryFromProto(logEntry *common.LogEntry) *LogEntry { + var fields []*map[string]interface{} + for _, field := range logEntry.Fields { + f := field.AsMap() + fields = append(fields, &f) + } + caller := logEntry.Caller.AsMap() + return &LogEntry{ + Host: logEntry.Host, + Level: logEntry.Level, + Time: logEntry.Time, + LoggerName: logEntry.LoggerName, + Message: logEntry.Message, + Caller: &caller, + Stack: logEntry.Stack, + Fields: fields, + } +} + +// Fragment stores the information of a fragment. +type Fragment struct { + ID string + Name string + Fragment *map[string]interface{} + OrganizationOwner string + Public bool + CreatedOn *timestamppb.Timestamp + OrganizationName string + RobotPartCount int32 + OrganizationCount int32 + OnlyUsedByOwner bool + Visibility FragmentVisibility + LastUpdated *timestamppb.Timestamp +} + +func fragmentFromProto(fragment *pb.Fragment) *Fragment { + f := fragment.Fragment.AsMap() + return &Fragment{ + ID: fragment.Id, + Name: fragment.Name, + Fragment: &f, + OrganizationOwner: fragment.OrganizationOwner, + Public: fragment.Public, + CreatedOn: fragment.CreatedOn, + OrganizationName: fragment.OrganizationName, + RobotPartCount: fragment.RobotPartCount, + OrganizationCount: fragment.OrganizationCount, + OnlyUsedByOwner: fragment.OnlyUsedByOwner, + Visibility: fragmentVisibilityFromProto(fragment.Visibility), + LastUpdated: fragment.LastUpdated, + } +} + +// FragmentVisibility specifies the kind of visibility a fragment has. +type FragmentVisibility int32 + +const ( + // FragmentVisibilityUnspecified is an unspecified visibility. + FragmentVisibilityUnspecified FragmentVisibility = iota + // FragmentVisibilityPrivate restricts access to a fragment to its organization. + FragmentVisibilityPrivate + // FragmentVisibilityPublic allows the fragment to be accessible to everyone. + FragmentVisibilityPublic + // FragmentVisibilityPublicUnlisted allows the fragment to be accessible to everyone but is hidden from public listings like it is private. + FragmentVisibilityPublicUnlisted +) + +func fragmentVisibilityFromProto(visibility pb.FragmentVisibility) FragmentVisibility { + switch visibility { + case pb.FragmentVisibility_FRAGMENT_VISIBILITY_UNSPECIFIED: + return FragmentVisibilityUnspecified + case pb.FragmentVisibility_FRAGMENT_VISIBILITY_PRIVATE: + return FragmentVisibilityPrivate + case pb.FragmentVisibility_FRAGMENT_VISIBILITY_PUBLIC: + return FragmentVisibilityPublic + case pb.FragmentVisibility_FRAGMENT_VISIBILITY_PUBLIC_UNLISTED: + return FragmentVisibilityPublicUnlisted + } + return FragmentVisibilityUnspecified +} + +func fragmentVisibilityToProto(visibility FragmentVisibility) pb.FragmentVisibility { + switch visibility { + case FragmentVisibilityUnspecified: + return pb.FragmentVisibility_FRAGMENT_VISIBILITY_UNSPECIFIED + case FragmentVisibilityPrivate: + return pb.FragmentVisibility_FRAGMENT_VISIBILITY_PRIVATE + case FragmentVisibilityPublic: + return pb.FragmentVisibility_FRAGMENT_VISIBILITY_PUBLIC + case FragmentVisibilityPublicUnlisted: + return pb.FragmentVisibility_FRAGMENT_VISIBILITY_PUBLIC_UNLISTED + } + return pb.FragmentVisibility_FRAGMENT_VISIBILITY_UNSPECIFIED +} + +// FragmentHistoryEntry is an entry of a fragment's history. +type FragmentHistoryEntry struct { + Fragment string + EditedOn *timestamppb.Timestamp + Old *Fragment + EditedBy *AuthenticatorInfo +} + +func fragmentHistoryEntryFromProto(entry *pb.FragmentHistoryEntry) *FragmentHistoryEntry { + return &FragmentHistoryEntry{ + Fragment: entry.Fragment, + EditedOn: entry.EditedOn, + Old: fragmentFromProto(entry.Old), + EditedBy: authenticatorInfoFromProto(entry.EditedBy), + } +} + +// Authorization has the information about a specific authorization. +type Authorization struct { + AuthorizationType string + AuthorizationID string + ResourceType string + ResourceID string + IdentityID string + OrganizationID string + IdentityType string +} + +func authorizationFromProto(authorization *pb.Authorization) *Authorization { + return &Authorization{ + AuthorizationType: authorization.AuthorizationType, + AuthorizationID: authorization.AuthorizationId, + ResourceType: authorization.ResourceType, + ResourceID: authorization.ResourceId, + IdentityID: authorization.IdentityId, + OrganizationID: authorization.OrganizationId, + IdentityType: authorization.IdentityType, + } +} + +func authorizationToProto(authorization *Authorization) *pb.Authorization { + return &pb.Authorization{ + AuthorizationType: authorization.AuthorizationType, + AuthorizationId: authorization.AuthorizationID, + ResourceType: authorization.ResourceType, + ResourceId: authorization.ResourceID, + IdentityId: authorization.IdentityID, + OrganizationId: authorization.OrganizationID, + IdentityType: authorization.IdentityType, + } +} + +// AuthorizedPermissions is authorized permissions. +type AuthorizedPermissions struct { + ResourceType string + ResourceID string + Permissions []string +} + +func authorizedPermissionsFromProto(permissions *pb.AuthorizedPermissions) *AuthorizedPermissions { + return &AuthorizedPermissions{ + ResourceType: permissions.ResourceType, + ResourceID: permissions.ResourceId, + Permissions: permissions.Permissions, + } +} + +func authorizedPermissionsToProto(permissions *AuthorizedPermissions) *pb.AuthorizedPermissions { + return &pb.AuthorizedPermissions{ + ResourceType: permissions.ResourceType, + ResourceId: permissions.ResourceID, + Permissions: permissions.Permissions, + } +} + +// APIKeyAuthorization is a struct with the necessary authorization data to create an API key. +type APIKeyAuthorization struct { + // `role`` must be "owner" or "operator" + role string + // `resourceType` must be "organization", "location", or "robot" + resourceType string + resourceID string +} + +func createAuthorization(orgID, identityID, identityType, role, resourceType, resourceID string) (*pb.Authorization, error) { + if role != "owner" && role != "operator" { + return nil, errors.New("role string must be 'owner' or 'operator'") + } + if resourceType != "organization" && resourceType != "location" && resourceType != "robot" { + return nil, errors.New("resourceType must be 'organization', 'location', or 'robot'") + } + + return &pb.Authorization{ + AuthorizationType: role, + AuthorizationId: fmt.Sprintf("%s_%s", resourceType, role), + ResourceType: resourceType, + ResourceId: resourceID, + IdentityId: identityID, + OrganizationId: orgID, + IdentityType: identityType, + }, nil +} + +// SharedSecret is a secret used for LocationAuth and RobotParts. +type SharedSecret struct { + ID string + CreatedOn *timestamppb.Timestamp + State SharedSecretState +} + +func sharedSecretFromProto(sharedSecret *pb.SharedSecret) *SharedSecret { + return &SharedSecret{ + ID: sharedSecret.Id, + CreatedOn: sharedSecret.CreatedOn, + State: sharedSecretStateFromProto(sharedSecret.State), + } +} + +// SharedSecretState specifies if the secret is enabled, disabled, or unspecified. +type SharedSecretState int32 + +const ( + // SharedSecretStateUnspecified represents an unspecified shared secret state. + SharedSecretStateUnspecified SharedSecretState = iota + // SharedSecretStateEnabled represents an enabled secret that can be used in authentication. + SharedSecretStateEnabled + // SharedSecretStateDisabled represents a disabled secret that must not be used to authenticate to rpc. + SharedSecretStateDisabled +) + +func sharedSecretStateFromProto(state pb.SharedSecret_State) SharedSecretState { + switch state { + case pb.SharedSecret_STATE_UNSPECIFIED: + return SharedSecretStateUnspecified + case pb.SharedSecret_STATE_ENABLED: + return SharedSecretStateEnabled + case pb.SharedSecret_STATE_DISABLED: + return SharedSecretStateDisabled + default: + return SharedSecretStateUnspecified + } +} + +// AuthenticatorInfo holds the information of an authenticator. +type AuthenticatorInfo struct { + Type AuthenticationType + Value string + IsDeactivated bool +} + +func authenticatorInfoFromProto(info *pb.AuthenticatorInfo) *AuthenticatorInfo { + return &AuthenticatorInfo{ + Type: authenticationTypeFromProto(info.Type), + Value: info.Value, + IsDeactivated: info.IsDeactivated, + } +} + +// AuthenticationType specifies the type of authentication. +type AuthenticationType int32 + +const ( + // AuthenticationTypeUnspecified represents an unspecified authentication. + AuthenticationTypeUnspecified AuthenticationType = iota + // AuthenticationTypeWebOAuth represents authentication using Web OAuth. + AuthenticationTypeWebOAuth + // AuthenticationTypeAPIKey represents authentication using an API key. + AuthenticationTypeAPIKey + // AuthenticationTypeRobotPartSecret represents authentication using a robot part secret. + AuthenticationTypeRobotPartSecret + // AuthenticationTypeLocationSecret represents authentication using a location secret. + AuthenticationTypeLocationSecret +) + +func authenticationTypeFromProto(authenticationType pb.AuthenticationType) AuthenticationType { + switch authenticationType { + case pb.AuthenticationType_AUTHENTICATION_TYPE_UNSPECIFIED: + return AuthenticationTypeUnspecified + case pb.AuthenticationType_AUTHENTICATION_TYPE_WEB_OAUTH: + return AuthenticationTypeWebOAuth + case pb.AuthenticationType_AUTHENTICATION_TYPE_API_KEY: + return AuthenticationTypeAPIKey + case pb.AuthenticationType_AUTHENTICATION_TYPE_ROBOT_PART_SECRET: + return AuthenticationTypeRobotPartSecret + case pb.AuthenticationType_AUTHENTICATION_TYPE_LOCATION_SECRET: + return AuthenticationTypeLocationSecret + } + return AuthenticationTypeUnspecified +} + +// APIKeyWithAuthorizations is an API Key with its authorizations. +type APIKeyWithAuthorizations struct { + APIKey *APIKey + Authorizations []*AuthorizationDetails +} + +func apiKeyWithAuthorizationsFromProto(key *pb.APIKeyWithAuthorizations) *APIKeyWithAuthorizations { + var details []*AuthorizationDetails + for _, detail := range key.Authorizations { + details = append(details, authorizationDetailsFromProto(detail)) + } + return &APIKeyWithAuthorizations{ + APIKey: apiKeyFromProto(key.ApiKey), + Authorizations: details, + } +} + +// APIKey is a API key to make a request to an API. +type APIKey struct { + ID string + Key string + Name string + CreatedOn *timestamppb.Timestamp +} + +func apiKeyFromProto(key *pb.APIKey) *APIKey { + return &APIKey{ + ID: key.Id, + Key: key.Key, + Name: key.Name, + CreatedOn: key.CreatedOn, + } +} + +// AuthorizationDetails has the details for an authorization. +type AuthorizationDetails struct { + AuthorizationType string + AuthorizationID string + ResourceType string + ResourceID string + OrgID string +} + +func authorizationDetailsFromProto(details *pb.AuthorizationDetails) *AuthorizationDetails { + return &AuthorizationDetails{ + AuthorizationType: details.AuthorizationType, + AuthorizationID: details.AuthorizationId, + ResourceType: details.ResourceType, + ResourceID: details.ResourceId, + OrgID: details.OrgId, + } +} diff --git a/app/data_client.go b/app/data_client.go index 8578eefc9e2..2415852548b 100644 --- a/app/data_client.go +++ b/app/data_client.go @@ -177,7 +177,7 @@ type DatabaseConnReturn struct { HasDatabaseUser bool } -// NewDataClient constructs a new DataClient using the connection passed in by the viamClient. +// NewDataClient constructs a new DataClient using the connection passed in by the Viam client. func NewDataClient( conn rpc.ClientConn, ) *DataClient { diff --git a/app/data_client_test.go b/app/data_client_test.go index 5a3a22468a0..d16dd382639 100644 --- a/app/data_client_test.go +++ b/app/data_client_test.go @@ -16,27 +16,26 @@ import ( ) const ( - componentName = "component_name" - componentType = "component_type" - method = "method" - robotName = "robot_name" - robotID = "robot_id" - partName = "part_name" - partID = "part_id" - locationID = "location_id" - organizationID = "organization_id" - password = "password" - mimeType = "mime_type" - uri = "some.robot.uri" - bboxLabel = "bbox_label" - tag = "tag" - fileName = "file_name" - fileExt = "file_ext.ext" - datasetID = "dataset_id" - binaryMetaID = "binary_id" - mongodbURI = "mongo_uri" - hostName = "host_name" - last = "last" + componentName = "component_name" + componentType = "component_type" + method = "method" + robotName = "robot_name" + robotID = "robot_id" + partName = "part_name" + partID = "part_id" + locationID = "location_id" + password = "password" + mimeType = "mime_type" + uri = "some.robot.uri" + bboxLabel = "bbox_label" + tag = "tag" + fileName = "file_name" + fileExt = "file_ext.ext" + datasetID = "dataset_id" + binaryMetaID = "binary_id" + mongodbURI = "mongo_uri" + hostName = "host_name" + last = "last" ) var ( @@ -153,12 +152,12 @@ func dataRequestToProto(dataRequest DataRequest) *pb.DataRequest { } } -func createGrpcClient() *inject.DataServiceClient { +func createDataGrpcClient() *inject.DataServiceClient { return &inject.DataServiceClient{} } func TestDataClient(t *testing.T) { - grpcClient := createGrpcClient() + grpcClient := createDataGrpcClient() client := DataClient{client: grpcClient} captureInterval := CaptureInterval{ diff --git a/app/registry_proto_conversions.go b/app/registry_proto_conversions.go new file mode 100644 index 00000000000..f4937b2c55c --- /dev/null +++ b/app/registry_proto_conversions.go @@ -0,0 +1,484 @@ +package app + +import ( + "fmt" + + mlTraining "go.viam.com/api/app/mltraining/v1" + packages "go.viam.com/api/app/packages/v1" + pb "go.viam.com/api/app/v1" + "google.golang.org/protobuf/types/known/timestamppb" +) + +// RegistryItem has the information of an item in the registry. +type RegistryItem struct { + ItemID string + OrganizationID string + PublicNamespace string + Name string + Type PackageType + Visibility Visibility + URL string + Description string + TotalRobotUsage int64 + TotalExternalRobotUsage int64 + TotalOrganizationUsage int64 + TotalExternalOrganizationUsage int64 + Metadata isRegistryItemMetadata + CreatedAt *timestamppb.Timestamp + UpdatedAt *timestamppb.Timestamp +} + +func registryItemFromProto(item *pb.RegistryItem) (*RegistryItem, error) { + var metadata isRegistryItemMetadata + switch pbMetadata := item.Metadata.(type) { + case *pb.RegistryItem_ModuleMetadata: + metadata = ®istryItemModuleMetadata{ModuleMetadata: moduleMetadataFromProto(pbMetadata.ModuleMetadata)} + case *pb.RegistryItem_MlModelMetadata: + metadata = ®istryItemMLModelMetadata{MlModelMetadata: mlModelMetadataFromProto(pbMetadata.MlModelMetadata)} + case *pb.RegistryItem_MlTrainingMetadata: + metadata = ®istryItemMLTrainingMetadata{MlTrainingMetadata: mlTrainingMetadataFromProto(pbMetadata.MlTrainingMetadata)} + default: + return nil, fmt.Errorf("unknown registry item metadata type: %T", item.Metadata) + } + + return &RegistryItem{ + ItemID: item.ItemId, + OrganizationID: item.OrganizationId, + PublicNamespace: item.PublicNamespace, + Name: item.Name, + Type: packageTypeFromProto(item.Type), + Visibility: visibilityFromProto(item.Visibility), + URL: item.Url, + Description: item.Description, + TotalRobotUsage: item.TotalRobotUsage, + TotalExternalRobotUsage: item.TotalExternalRobotUsage, + TotalOrganizationUsage: item.TotalOrganizationUsage, + TotalExternalOrganizationUsage: item.TotalExternalOrganizationUsage, + Metadata: metadata, + CreatedAt: item.CreatedAt, + UpdatedAt: item.UpdatedAt, + }, nil +} + +// RegistryItemStatus specifies if a registry item is published or in development. +type RegistryItemStatus int32 + +const ( + // RegistryItemStatusUnspecified is an unspecified registry item status. + RegistryItemStatusUnspecified RegistryItemStatus = iota + // RegistryItemStatusPublished represents a published registry item. + RegistryItemStatusPublished + // RegistryItemStatusInDevelopment represents a registry item still in development. + RegistryItemStatusInDevelopment +) + +func registryItemStatusToProto(status RegistryItemStatus) pb.RegistryItemStatus { + switch status { + case RegistryItemStatusUnspecified: + return pb.RegistryItemStatus_REGISTRY_ITEM_STATUS_UNSPECIFIED + case RegistryItemStatusPublished: + return pb.RegistryItemStatus_REGISTRY_ITEM_STATUS_PUBLISHED + case RegistryItemStatusInDevelopment: + return pb.RegistryItemStatus_REGISTRY_ITEM_STATUS_IN_DEVELOPMENT + } + return pb.RegistryItemStatus_REGISTRY_ITEM_STATUS_UNSPECIFIED +} + +// PackageType is the type of package being used. +type PackageType int32 + +const ( + // PackageTypeUnspecified represents an unspecified package type. + PackageTypeUnspecified PackageType = iota + // PackageTypeArchive represents an archive package type. + PackageTypeArchive + // PackageTypeMLModel represents a ML model package type. + PackageTypeMLModel + // PackageTypeModule represents a module package type. + PackageTypeModule + // PackageTypeSLAMMap represents a SLAM map package type. + PackageTypeSLAMMap + // PackageTypeMLTraining represents a ML training package type. + PackageTypeMLTraining +) + +func packageTypeFromProto(packageType packages.PackageType) PackageType { + switch packageType { + case packages.PackageType_PACKAGE_TYPE_UNSPECIFIED: + return PackageTypeUnspecified + case packages.PackageType_PACKAGE_TYPE_ARCHIVE: + return PackageTypeArchive + case packages.PackageType_PACKAGE_TYPE_ML_MODEL: + return PackageTypeMLModel + case packages.PackageType_PACKAGE_TYPE_MODULE: + return PackageTypeModule + case packages.PackageType_PACKAGE_TYPE_SLAM_MAP: + return PackageTypeSLAMMap + case packages.PackageType_PACKAGE_TYPE_ML_TRAINING: + return PackageTypeMLTraining + } + return PackageTypeUnspecified +} + +func packageTypeToProto(packageType PackageType) packages.PackageType { + switch packageType { + case PackageTypeUnspecified: + return packages.PackageType_PACKAGE_TYPE_UNSPECIFIED + case PackageTypeArchive: + return packages.PackageType_PACKAGE_TYPE_ARCHIVE + case PackageTypeMLModel: + return packages.PackageType_PACKAGE_TYPE_ML_MODEL + case PackageTypeModule: + return packages.PackageType_PACKAGE_TYPE_MODULE + case PackageTypeSLAMMap: + return packages.PackageType_PACKAGE_TYPE_SLAM_MAP + case PackageTypeMLTraining: + return packages.PackageType_PACKAGE_TYPE_ML_TRAINING + } + return packages.PackageType_PACKAGE_TYPE_UNSPECIFIED +} + +// Visibility specifies the type of visibility of a registry item. +type Visibility int32 + +const ( + // VisibilityUnspecified represents an unspecified visibility. + VisibilityUnspecified Visibility = iota + // VisibilityPrivate are for registry items visible only within the owning org. + VisibilityPrivate + // VisibilityPublic are for registry items that are visible to everyone. + VisibilityPublic + // VisibilityPublicUnlisted are for registry items usable in everyone's robot but are hidden from the registry page as if they are private. + VisibilityPublicUnlisted +) + +func visibilityFromProto(visibility pb.Visibility) Visibility { + switch visibility { + case pb.Visibility_VISIBILITY_UNSPECIFIED: + return VisibilityUnspecified + case pb.Visibility_VISIBILITY_PRIVATE: + return VisibilityPrivate + case pb.Visibility_VISIBILITY_PUBLIC: + return VisibilityPublic + case pb.Visibility_VISIBILITY_PUBLIC_UNLISTED: + return VisibilityPublicUnlisted + } + return VisibilityUnspecified +} + +func visibilityToProto(visibility Visibility) pb.Visibility { + switch visibility { + case VisibilityUnspecified: + return pb.Visibility_VISIBILITY_UNSPECIFIED + case VisibilityPrivate: + return pb.Visibility_VISIBILITY_PRIVATE + case VisibilityPublic: + return pb.Visibility_VISIBILITY_PUBLIC + case VisibilityPublicUnlisted: + return pb.Visibility_VISIBILITY_PUBLIC_UNLISTED + } + return pb.Visibility_VISIBILITY_UNSPECIFIED +} + +type isRegistryItemMetadata interface { + isRegistryItemMetadata() +} + +type registryItemModuleMetadata struct { + ModuleMetadata *ModuleMetadata +} + +type registryItemMLModelMetadata struct { + MlModelMetadata *MLModelMetadata +} + +type registryItemMLTrainingMetadata struct { + MlTrainingMetadata *MLTrainingMetadata +} + +func (*registryItemModuleMetadata) isRegistryItemMetadata() {} + +func (*registryItemMLModelMetadata) isRegistryItemMetadata() {} + +func (*registryItemMLTrainingMetadata) isRegistryItemMetadata() {} + +// ModuleMetadata holds the metadata of a module. +type ModuleMetadata struct { + Models []*Model + Versions []*ModuleVersion + Entrypoint string + FirstRun *string +} + +func moduleMetadataFromProto(md *pb.ModuleMetadata) *ModuleMetadata { + var models []*Model + for _, version := range md.Models { + models = append(models, modelFromProto(version)) + } + var versions []*ModuleVersion + for _, version := range md.Versions { + versions = append(versions, moduleVersionFromProto(version)) + } + return &ModuleMetadata{ + Models: models, + Versions: versions, + Entrypoint: md.Entrypoint, + FirstRun: md.FirstRun, + } +} + +// Model has the API and model of a model. +type Model struct { + API string + Model string +} + +func modelFromProto(model *pb.Model) *Model { + return &Model{ + API: model.Api, + Model: model.Model, + } +} + +func modelToProto(model *Model) *pb.Model { + return &pb.Model{ + Api: model.API, + Model: model.Model, + } +} + +// ModuleVersion holds the information of a module version. +type ModuleVersion struct { + Version string + Files []*Uploads + Models []*Model + Entrypoint string + FirstRun *string +} + +func moduleVersionFromProto(version *pb.ModuleVersion) *ModuleVersion { + var files []*Uploads + for _, file := range version.Files { + files = append(files, uploadsFromProto(file)) + } + var models []*Model + for _, model := range version.Models { + models = append(models, modelFromProto(model)) + } + return &ModuleVersion{ + Version: version.Version, + Files: files, + Models: models, + Entrypoint: version.Entrypoint, + FirstRun: version.FirstRun, + } +} + +// Uploads holds the time the file was uploaded and the OS and architecture a module is built to run on. +type Uploads struct { + Platform string + UploadedAt *timestamppb.Timestamp +} + +func uploadsFromProto(uploads *pb.Uploads) *Uploads { + return &Uploads{ + Platform: uploads.Platform, + UploadedAt: uploads.UploadedAt, + } +} + +// MLModelMetadata holds the metadata for a ML model. +type MLModelMetadata struct { + Versions []string + ModelType ModelType + ModelFramework ModelFramework +} + +func mlModelMetadataFromProto(md *pb.MLModelMetadata) *MLModelMetadata { + return &MLModelMetadata{ + Versions: md.Versions, + ModelType: modelTypeFromProto(md.ModelType), + ModelFramework: modelFrameworkFromProto(md.ModelFramework), + } +} + +// ModelType specifies the type of model used for classification or detection. +type ModelType int32 + +const ( + // ModelTypeUnspecified represents an unspecified model. + ModelTypeUnspecified ModelType = iota + // ModelTypeSingleLabelClassification represents a single-label classification model. + ModelTypeSingleLabelClassification + // ModelTypeMultiLabelClassification represents a multi-label classification model. + ModelTypeMultiLabelClassification + // ModelTypeObjectDetection represents an object detection model. + ModelTypeObjectDetection +) + +func modelTypeFromProto(modelType mlTraining.ModelType) ModelType { + switch modelType { + case mlTraining.ModelType_MODEL_TYPE_UNSPECIFIED: + return ModelTypeUnspecified + case mlTraining.ModelType_MODEL_TYPE_SINGLE_LABEL_CLASSIFICATION: + return ModelTypeSingleLabelClassification + case mlTraining.ModelType_MODEL_TYPE_MULTI_LABEL_CLASSIFICATION: + return ModelTypeMultiLabelClassification + case mlTraining.ModelType_MODEL_TYPE_OBJECT_DETECTION: + return ModelTypeObjectDetection + } + return ModelTypeUnspecified +} + +// ModelFramework is the framework type of a model. +type ModelFramework int32 + +const ( + // ModelFrameworkUnspecified is an unspecified model framework. + ModelFrameworkUnspecified ModelFramework = iota + // ModelFrameworkTFLite specifies a TFLite model framework. + ModelFrameworkTFLite + // ModelFrameworkTensorFlow specifies a TensorFlow model framework. + ModelFrameworkTensorFlow + // ModelFrameworkPyTorch specifies a PyTorch model framework. + ModelFrameworkPyTorch + // ModelFrameworkONNX specifies a ONNX model framework. + ModelFrameworkONNX +) + +func modelFrameworkFromProto(framework mlTraining.ModelFramework) ModelFramework { + switch framework { + case mlTraining.ModelFramework_MODEL_FRAMEWORK_UNSPECIFIED: + return ModelFrameworkUnspecified + case mlTraining.ModelFramework_MODEL_FRAMEWORK_TFLITE: + return ModelFrameworkTFLite + case mlTraining.ModelFramework_MODEL_FRAMEWORK_TENSORFLOW: + return ModelFrameworkTensorFlow + case mlTraining.ModelFramework_MODEL_FRAMEWORK_PYTORCH: + return ModelFrameworkPyTorch + case mlTraining.ModelFramework_MODEL_FRAMEWORK_ONNX: + return ModelFrameworkONNX + } + return ModelFrameworkUnspecified +} + +// MLTrainingMetadata is the metadata of an ML Training. +type MLTrainingMetadata struct { + Versions []*MLTrainingVersion + ModelType ModelType + ModelFramework ModelFramework + Draft bool +} + +func mlTrainingMetadataFromProto(md *pb.MLTrainingMetadata) *MLTrainingMetadata { + var versions []*MLTrainingVersion + for _, version := range md.Versions { + versions = append(versions, mlTrainingVersionFromProto(version)) + } + return &MLTrainingMetadata{ + Versions: versions, + ModelType: modelTypeFromProto(md.ModelType), + ModelFramework: modelFrameworkFromProto(md.ModelFramework), + Draft: md.Draft, + } +} + +// MLTrainingVersion is the version of ML Training. +type MLTrainingVersion struct { + Version string + CreatedOn *timestamppb.Timestamp +} + +func mlTrainingVersionFromProto(version *pb.MLTrainingVersion) *MLTrainingVersion { + return &MLTrainingVersion{ + Version: version.Version, + CreatedOn: version.CreatedOn, + } +} + +// Module holds the information of a module. +type Module struct { + ModuleID string + Name string + Visibility Visibility + Versions []*VersionHistory + URL string + Description string + Models []*Model + TotalRobotUsage int64 + TotalOrganizationUsage int64 + OrganizationID string + Entrypoint string + PublicNamespace string + FirstRun *string +} + +func moduleFromProto(module *pb.Module) *Module { + var versions []*VersionHistory + for _, version := range module.Versions { + versions = append(versions, versionHistoryFromProto(version)) + } + var models []*Model + for _, model := range module.Models { + models = append(models, modelFromProto(model)) + } + return &Module{ + ModuleID: module.ModuleId, + Name: module.Name, + Visibility: visibilityFromProto(module.Visibility), + Versions: versions, + URL: module.Url, + Description: module.Description, + Models: models, + TotalRobotUsage: module.TotalRobotUsage, + TotalOrganizationUsage: module.TotalOrganizationUsage, + OrganizationID: module.OrganizationId, + Entrypoint: module.Entrypoint, + PublicNamespace: module.PublicNamespace, + FirstRun: module.FirstRun, + } +} + +// ModuleFileInfo holds the information of a module file. +type ModuleFileInfo struct { + ModuleID string + Version string + Platform string + PlatformTags []string +} + +func moduleFileInfoToProto(info *ModuleFileInfo) *pb.ModuleFileInfo { + return &pb.ModuleFileInfo{ + ModuleId: info.ModuleID, + Version: info.Version, + Platform: info.Platform, + PlatformTags: info.PlatformTags, + } +} + +// VersionHistory holds the history of a version. +type VersionHistory struct { + Version string + Files []*Uploads + Models []*Model + Entrypoint string + FirstRun *string +} + +func versionHistoryFromProto(history *pb.VersionHistory) *VersionHistory { + var files []*Uploads + for _, file := range history.Files { + files = append(files, uploadsFromProto(file)) + } + var models []*Model + for _, model := range history.Models { + models = append(models, modelFromProto(model)) + } + return &VersionHistory{ + Version: history.Version, + Files: files, + Models: models, + Entrypoint: history.Entrypoint, + FirstRun: history.FirstRun, + } +} diff --git a/app/viam_client.go b/app/viam_client.go index 6a8e3075012..4c69c45c31a 100644 --- a/app/viam_client.go +++ b/app/viam_client.go @@ -15,6 +15,7 @@ import ( // ViamClient is a gRPC client for method calls to Viam app. type ViamClient struct { conn rpc.ClientConn + appClient *AppClient dataClient *DataClient } @@ -63,6 +64,16 @@ func CreateViamClientWithAPIKey( return CreateViamClientWithOptions(ctx, options, logger) } +// AppClient initializes and returns an AppClient instance used to make app method calls. +// To use AppClient, you must first instantiate a ViamClient. +func (c *ViamClient) AppClient() *AppClient { + if c.appClient != nil { + return c.appClient + } + c.appClient = NewAppClient(c.conn) + return c.appClient +} + // DataClient initializes and returns a DataClient instance used to make data method calls. // To use DataClient, you must first instantiate a ViamClient. func (c *ViamClient) DataClient() *DataClient { diff --git a/app/viam_client_test.go b/app/viam_client_test.go index 08b93ad1c31..51a624371cd 100644 --- a/app/viam_client_test.go +++ b/app/viam_client_test.go @@ -5,7 +5,8 @@ import ( "testing" "github.com/viamrobotics/webrtc/v3" - pb "go.viam.com/api/app/data/v1" + datapb "go.viam.com/api/app/data/v1" + apppb "go.viam.com/api/app/v1" "go.viam.com/test" "go.viam.com/utils" "go.viam.com/utils/rpc" @@ -119,7 +120,7 @@ func TestCreateViamClientWithAPIKeyTests(t *testing.T) { } } -func TestNewDataClient(t *testing.T) { +func TestNewAppClients(t *testing.T) { originalDialDirectGRPC := dialDirectGRPC dialDirectGRPC = mockDialDirectGRPC defer func() { dialDirectGRPC = originalDialDirectGRPC }() @@ -138,10 +139,20 @@ func TestNewDataClient(t *testing.T) { dataClient := client.DataClient() test.That(t, dataClient, test.ShouldNotBeNil) test.That(t, dataClient, test.ShouldHaveSameTypeAs, &DataClient{}) - test.That(t, dataClient.client, test.ShouldImplement, (*pb.DataServiceClient)(nil)) + test.That(t, dataClient.client, test.ShouldImplement, (*datapb.DataServiceClient)(nil)) // Testing that a second call to DataClient() returns the same instance dataClient2 := client.DataClient() test.That(t, dataClient2, test.ShouldNotBeNil) - test.That(t, dataClient, test.ShouldResemble, dataClient2) + test.That(t, dataClient, test.ShouldEqual, dataClient2) + + appClient := client.AppClient() + test.That(t, appClient, test.ShouldNotBeNil) + test.That(t, appClient, test.ShouldHaveSameTypeAs, &AppClient{}) + test.That(t, appClient.client, test.ShouldImplement, (*apppb.AppServiceClient)(nil)) + + // Testing that a second call to AppClient() returns the same instance + appClient2 := client.AppClient() + test.That(t, appClient2, test.ShouldNotBeNil) + test.That(t, appClient, test.ShouldEqual, appClient2) } diff --git a/testutils/inject/app_service_client.go b/testutils/inject/app_service_client.go index 5cffed32d2f..bc31925078b 100644 --- a/testutils/inject/app_service_client.go +++ b/testutils/inject/app_service_client.go @@ -10,29 +10,186 @@ import ( // AppServiceClient represents a fake instance of an app service client. type AppServiceClient struct { apppb.AppServiceClient + GetUserIDByEmailFunc func(ctx context.Context, in *apppb.GetUserIDByEmailRequest, + opts ...grpc.CallOption) (*apppb.GetUserIDByEmailResponse, error) + CreateOrganizationFunc func(ctx context.Context, in *apppb.CreateOrganizationRequest, + opts ...grpc.CallOption) (*apppb.CreateOrganizationResponse, error) ListOrganizationsFunc func(ctx context.Context, in *apppb.ListOrganizationsRequest, opts ...grpc.CallOption) (*apppb.ListOrganizationsResponse, error) + GetOrganizationsWithAccessToLocationFunc func(ctx context.Context, in *apppb.GetOrganizationsWithAccessToLocationRequest, + opts ...grpc.CallOption) (*apppb.GetOrganizationsWithAccessToLocationResponse, error) + ListOrganizationsByUserFunc func(ctx context.Context, in *apppb.ListOrganizationsByUserRequest, + opts ...grpc.CallOption) (*apppb.ListOrganizationsByUserResponse, error) + GetOrganizationFunc func(ctx context.Context, in *apppb.GetOrganizationRequest, + opts ...grpc.CallOption) (*apppb.GetOrganizationResponse, error) + GetOrganizationNamespaceAvailabilityFunc func(ctx context.Context, in *apppb.GetOrganizationNamespaceAvailabilityRequest, + opts ...grpc.CallOption) (*apppb.GetOrganizationNamespaceAvailabilityResponse, error) + UpdateOrganizationFunc func(ctx context.Context, in *apppb.UpdateOrganizationRequest, + opts ...grpc.CallOption) (*apppb.UpdateOrganizationResponse, error) + DeleteOrganizationFunc func(ctx context.Context, in *apppb.DeleteOrganizationRequest, + opts ...grpc.CallOption) (*apppb.DeleteOrganizationResponse, error) + ListOrganizationMembersFunc func(ctx context.Context, in *apppb.ListOrganizationMembersRequest, + opts ...grpc.CallOption) (*apppb.ListOrganizationMembersResponse, error) + CreateOrganizationInviteFunc func(ctx context.Context, in *apppb.CreateOrganizationInviteRequest, + opts ...grpc.CallOption) (*apppb.CreateOrganizationInviteResponse, error) + UpdateOrganizationInviteAuthorizationsFunc func(ctx context.Context, in *apppb.UpdateOrganizationInviteAuthorizationsRequest, + opts ...grpc.CallOption) (*apppb.UpdateOrganizationInviteAuthorizationsResponse, error) + DeleteOrganizationMemberFunc func(ctx context.Context, in *apppb.DeleteOrganizationMemberRequest, + opts ...grpc.CallOption) (*apppb.DeleteOrganizationMemberResponse, error) + DeleteOrganizationInviteFunc func(ctx context.Context, in *apppb.DeleteOrganizationInviteRequest, + opts ...grpc.CallOption) (*apppb.DeleteOrganizationInviteResponse, error) + ResendOrganizationInviteFunc func(ctx context.Context, in *apppb.ResendOrganizationInviteRequest, + opts ...grpc.CallOption) (*apppb.ResendOrganizationInviteResponse, error) + EnableBillingServiceFunc func(ctx context.Context, in *apppb.EnableBillingServiceRequest, + opts ...grpc.CallOption) (*apppb.EnableBillingServiceResponse, error) + DisableBillingServiceFunc func(ctx context.Context, in *apppb.DisableBillingServiceRequest, + opts ...grpc.CallOption) (*apppb.DisableBillingServiceResponse, error) + UpdateBillingServiceFunc func(ctx context.Context, in *apppb.UpdateBillingServiceRequest, + opts ...grpc.CallOption) (*apppb.UpdateBillingServiceResponse, error) + OrganizationSetSupportEmailFunc func(ctx context.Context, in *apppb.OrganizationSetSupportEmailRequest, + opts ...grpc.CallOption) (*apppb.OrganizationSetSupportEmailResponse, error) + OrganizationGetSupportEmailFunc func(ctx context.Context, in *apppb.OrganizationGetSupportEmailRequest, + opts ...grpc.CallOption) (*apppb.OrganizationGetSupportEmailResponse, error) + CreateLocationFunc func(ctx context.Context, in *apppb.CreateLocationRequest, + opts ...grpc.CallOption) (*apppb.CreateLocationResponse, error) + GetLocationFunc func(ctx context.Context, in *apppb.GetLocationRequest, + opts ...grpc.CallOption) (*apppb.GetLocationResponse, error) + UpdateLocationFunc func(ctx context.Context, in *apppb.UpdateLocationRequest, + opts ...grpc.CallOption) (*apppb.UpdateLocationResponse, error) + DeleteLocationFunc func(ctx context.Context, in *apppb.DeleteLocationRequest, + opts ...grpc.CallOption) (*apppb.DeleteLocationResponse, error) ListLocationsFunc func(ctx context.Context, in *apppb.ListLocationsRequest, opts ...grpc.CallOption) (*apppb.ListLocationsResponse, error) - ListRobotsFunc func(ctx context.Context, in *apppb.ListRobotsRequest, - opts ...grpc.CallOption) (*apppb.ListRobotsResponse, error) - CreateKeyFunc func(ctx context.Context, in *apppb.CreateKeyRequest, - opts ...grpc.CallOption) (*apppb.CreateKeyResponse, error) - GetRobotAPIKeysFunc func(ctx context.Context, in *apppb.GetRobotAPIKeysRequest, - opts ...grpc.CallOption) (*apppb.GetRobotAPIKeysResponse, error) - GetRobotPartFunc func(ctx context.Context, in *apppb.GetRobotPartRequest, - opts ...grpc.CallOption) (*apppb.GetRobotPartResponse, error) + ShareLocationFunc func(ctx context.Context, in *apppb.ShareLocationRequest, + opts ...grpc.CallOption) (*apppb.ShareLocationResponse, error) + UnshareLocationFunc func(ctx context.Context, in *apppb.UnshareLocationRequest, + opts ...grpc.CallOption) (*apppb.UnshareLocationResponse, error) + LocationAuthFunc func(ctx context.Context, in *apppb.LocationAuthRequest, + opts ...grpc.CallOption) (*apppb.LocationAuthResponse, error) + CreateLocationSecretFunc func(ctx context.Context, in *apppb.CreateLocationSecretRequest, + opts ...grpc.CallOption) (*apppb.CreateLocationSecretResponse, error) + DeleteLocationSecretFunc func(ctx context.Context, in *apppb.DeleteLocationSecretRequest, + opts ...grpc.CallOption) (*apppb.DeleteLocationSecretResponse, error) + GetRobotFunc func(ctx context.Context, in *apppb.GetRobotRequest, + opts ...grpc.CallOption) (*apppb.GetRobotResponse, error) + GetRoverRentalRobotsFunc func(ctx context.Context, in *apppb.GetRoverRentalRobotsRequest, + opts ...grpc.CallOption) (*apppb.GetRoverRentalRobotsResponse, error) GetRobotPartsFunc func(ctx context.Context, in *apppb.GetRobotPartsRequest, opts ...grpc.CallOption) (*apppb.GetRobotPartsResponse, error) + GetRobotPartFunc func(ctx context.Context, in *apppb.GetRobotPartRequest, + opts ...grpc.CallOption) (*apppb.GetRobotPartResponse, error) GetRobotPartLogsFunc func(ctx context.Context, in *apppb.GetRobotPartLogsRequest, opts ...grpc.CallOption) (*apppb.GetRobotPartLogsResponse, error) + TailRobotPartLogsFunc func(ctx context.Context, in *apppb.TailRobotPartLogsRequest, + opts ...grpc.CallOption) (apppb.AppService_TailRobotPartLogsClient, error) + GetRobotPartHistoryFunc func(ctx context.Context, in *apppb.GetRobotPartHistoryRequest, + opts ...grpc.CallOption) (*apppb.GetRobotPartHistoryResponse, error) UpdateRobotPartFunc func(ctx context.Context, in *apppb.UpdateRobotPartRequest, opts ...grpc.CallOption) (*apppb.UpdateRobotPartResponse, error) + NewRobotPartFunc func(ctx context.Context, in *apppb.NewRobotPartRequest, + opts ...grpc.CallOption) (*apppb.NewRobotPartResponse, error) + DeleteRobotPartFunc func(ctx context.Context, in *apppb.DeleteRobotPartRequest, + opts ...grpc.CallOption) (*apppb.DeleteRobotPartResponse, error) + GetRobotAPIKeysFunc func(ctx context.Context, in *apppb.GetRobotAPIKeysRequest, + opts ...grpc.CallOption) (*apppb.GetRobotAPIKeysResponse, error) + MarkPartAsMainFunc func(ctx context.Context, in *apppb.MarkPartAsMainRequest, + opts ...grpc.CallOption) (*apppb.MarkPartAsMainResponse, error) + MarkPartForRestartFunc func(ctx context.Context, in *apppb.MarkPartForRestartRequest, + opts ...grpc.CallOption) (*apppb.MarkPartForRestartResponse, error) + CreateRobotPartSecretFunc func(ctx context.Context, in *apppb.CreateRobotPartSecretRequest, + opts ...grpc.CallOption) (*apppb.CreateRobotPartSecretResponse, error) + DeleteRobotPartSecretFunc func(ctx context.Context, in *apppb.DeleteRobotPartSecretRequest, + opts ...grpc.CallOption) (*apppb.DeleteRobotPartSecretResponse, error) + ListRobotsFunc func(ctx context.Context, in *apppb.ListRobotsRequest, + opts ...grpc.CallOption) (*apppb.ListRobotsResponse, error) + NewRobotFunc func(ctx context.Context, in *apppb.NewRobotRequest, + opts ...grpc.CallOption) (*apppb.NewRobotResponse, error) + UpdateRobotFunc func(ctx context.Context, in *apppb.UpdateRobotRequest, + opts ...grpc.CallOption) (*apppb.UpdateRobotResponse, error) + DeleteRobotFunc func(ctx context.Context, in *apppb.DeleteRobotRequest, + opts ...grpc.CallOption) (*apppb.DeleteRobotResponse, error) + ListFragmentsFunc func(ctx context.Context, in *apppb.ListFragmentsRequest, + opts ...grpc.CallOption) (*apppb.ListFragmentsResponse, error) + GetFragmentFunc func(ctx context.Context, in *apppb.GetFragmentRequest, + opts ...grpc.CallOption) (*apppb.GetFragmentResponse, error) + CreateFragmentFunc func(ctx context.Context, in *apppb.CreateFragmentRequest, + opts ...grpc.CallOption) (*apppb.CreateFragmentResponse, error) + UpdateFragmentFunc func(ctx context.Context, in *apppb.UpdateFragmentRequest, + opts ...grpc.CallOption) (*apppb.UpdateFragmentResponse, error) + DeleteFragmentFunc func(ctx context.Context, in *apppb.DeleteFragmentRequest, + opts ...grpc.CallOption) (*apppb.DeleteFragmentResponse, error) + ListMachineFragmentsFunc func(ctx context.Context, in *apppb.ListMachineFragmentsRequest, + opts ...grpc.CallOption) (*apppb.ListMachineFragmentsResponse, error) + GetFragmentHistoryFunc func(ctx context.Context, in *apppb.GetFragmentHistoryRequest, + opts ...grpc.CallOption) (*apppb.GetFragmentHistoryResponse, error) + AddRoleFunc func(ctx context.Context, in *apppb.AddRoleRequest, + opts ...grpc.CallOption) (*apppb.AddRoleResponse, error) + RemoveRoleFunc func(ctx context.Context, in *apppb.RemoveRoleRequest, + opts ...grpc.CallOption) (*apppb.RemoveRoleResponse, error) + ChangeRoleFunc func(ctx context.Context, in *apppb.ChangeRoleRequest, + opts ...grpc.CallOption) (*apppb.ChangeRoleResponse, error) + ListAuthorizationsFunc func(ctx context.Context, in *apppb.ListAuthorizationsRequest, + opts ...grpc.CallOption) (*apppb.ListAuthorizationsResponse, error) + CheckPermissionsFunc func(ctx context.Context, in *apppb.CheckPermissionsRequest, + opts ...grpc.CallOption) (*apppb.CheckPermissionsResponse, error) + GetRegistryItemFunc func(ctx context.Context, in *apppb.GetRegistryItemRequest, + opts ...grpc.CallOption) (*apppb.GetRegistryItemResponse, error) + CreateRegistryItemFunc func(ctx context.Context, in *apppb.CreateRegistryItemRequest, + opts ...grpc.CallOption) (*apppb.CreateRegistryItemResponse, error) + UpdateRegistryItemFunc func(ctx context.Context, in *apppb.UpdateRegistryItemRequest, + opts ...grpc.CallOption) (*apppb.UpdateRegistryItemResponse, error) + ListRegistryItemsFunc func(ctx context.Context, in *apppb.ListRegistryItemsRequest, + opts ...grpc.CallOption) (*apppb.ListRegistryItemsResponse, error) + DeleteRegistryItemFunc func(ctx context.Context, in *apppb.DeleteRegistryItemRequest, + opts ...grpc.CallOption) (*apppb.DeleteRegistryItemResponse, error) + TransferRegistryItemFunc func(ctx context.Context, in *apppb.TransferRegistryItemRequest, + opts ...grpc.CallOption) (*apppb.TransferRegistryItemResponse, error) + CreateModuleFunc func(ctx context.Context, in *apppb.CreateModuleRequest, + opts ...grpc.CallOption) (*apppb.CreateModuleResponse, error) + UpdateModuleFunc func(ctx context.Context, in *apppb.UpdateModuleRequest, + opts ...grpc.CallOption) (*apppb.UpdateModuleResponse, error) + UploadModuleFileFunc func(ctx context.Context, opts ...grpc.CallOption) (apppb.AppService_UploadModuleFileClient, error) + GetModuleFunc func(ctx context.Context, in *apppb.GetModuleRequest, + opts ...grpc.CallOption) (*apppb.GetModuleResponse, error) + ListModulesFunc func(ctx context.Context, in *apppb.ListModulesRequest, + opts ...grpc.CallOption) (*apppb.ListModulesResponse, error) + CreateKeyFunc func(ctx context.Context, in *apppb.CreateKeyRequest, + opts ...grpc.CallOption) (*apppb.CreateKeyResponse, error) + DeleteKeyFunc func(ctx context.Context, in *apppb.DeleteKeyRequest, + opts ...grpc.CallOption) (*apppb.DeleteKeyResponse, error) + ListKeysFunc func(ctx context.Context, in *apppb.ListKeysRequest, + opts ...grpc.CallOption) (*apppb.ListKeysResponse, error) + RenameKeyFunc func(ctx context.Context, in *apppb.RenameKeyRequest, + opts ...grpc.CallOption) (*apppb.RenameKeyResponse, error) + RotateKeyFunc func(ctx context.Context, in *apppb.RotateKeyRequest, + opts ...grpc.CallOption) (*apppb.RotateKeyResponse, error) + CreateKeyFromExistingKeyAuthorizationsFunc func(ctx context.Context, in *apppb.CreateKeyFromExistingKeyAuthorizationsRequest, + opts ...grpc.CallOption) (*apppb.CreateKeyFromExistingKeyAuthorizationsResponse, error) +} + +// GetUserIDByEmail calls the injected GetUserIDByEmailFunc or the real version. +func (asc *AppServiceClient) GetUserIDByEmail( + ctx context.Context, in *apppb.GetUserIDByEmailRequest, opts ...grpc.CallOption, +) (*apppb.GetUserIDByEmailResponse, error) { + if asc.GetUserIDByEmailFunc == nil { + return asc.AppServiceClient.GetUserIDByEmail(ctx, in, opts...) + } + return asc.GetUserIDByEmailFunc(ctx, in, opts...) +} + +// CreateOrganization calls the injected CreateOrganizationFunc or the real version. +func (asc *AppServiceClient) CreateOrganization( + ctx context.Context, in *apppb.CreateOrganizationRequest, opts ...grpc.CallOption, +) (*apppb.CreateOrganizationResponse, error) { + if asc.CreateOrganizationFunc == nil { + return asc.AppServiceClient.CreateOrganization(ctx, in, opts...) + } + return asc.CreateOrganizationFunc(ctx, in, opts...) } // ListOrganizations calls the injected ListOrganizationsFunc or the real version. -func (asc *AppServiceClient) ListOrganizations(ctx context.Context, in *apppb.ListOrganizationsRequest, - opts ...grpc.CallOption, +func (asc *AppServiceClient) ListOrganizations( + ctx context.Context, in *apppb.ListOrganizationsRequest, opts ...grpc.CallOption, ) (*apppb.ListOrganizationsResponse, error) { if asc.ListOrganizationsFunc == nil { return asc.AppServiceClient.ListOrganizations(ctx, in, opts...) @@ -40,9 +197,219 @@ func (asc *AppServiceClient) ListOrganizations(ctx context.Context, in *apppb.Li return asc.ListOrganizationsFunc(ctx, in, opts...) } +// GetOrganizationsWithAccessToLocation calls the injected GetOrganizationsWithAccessToLocationFunc or the real version. +func (asc *AppServiceClient) GetOrganizationsWithAccessToLocation( + ctx context.Context, in *apppb.GetOrganizationsWithAccessToLocationRequest, opts ...grpc.CallOption, +) (*apppb.GetOrganizationsWithAccessToLocationResponse, error) { + if asc.GetOrganizationsWithAccessToLocationFunc == nil { + return asc.AppServiceClient.GetOrganizationsWithAccessToLocation(ctx, in, opts...) + } + return asc.GetOrganizationsWithAccessToLocationFunc(ctx, in, opts...) +} + +// ListOrganizationsByUser calls the injected ListOrganizationsByUserFunc or the real version. +func (asc *AppServiceClient) ListOrganizationsByUser( + ctx context.Context, in *apppb.ListOrganizationsByUserRequest, opts ...grpc.CallOption, +) (*apppb.ListOrganizationsByUserResponse, error) { + if asc.ListOrganizationsByUserFunc == nil { + return asc.AppServiceClient.ListOrganizationsByUser(ctx, in, opts...) + } + return asc.ListOrganizationsByUserFunc(ctx, in, opts...) +} + +// GetOrganization calls the injected GetOrganizationFunc or the real version. +func (asc *AppServiceClient) GetOrganization( + ctx context.Context, in *apppb.GetOrganizationRequest, opts ...grpc.CallOption, +) (*apppb.GetOrganizationResponse, error) { + if asc.GetOrganizationFunc == nil { + return asc.AppServiceClient.GetOrganization(ctx, in, opts...) + } + return asc.GetOrganizationFunc(ctx, in, opts...) +} + +// GetOrganizationNamespaceAvailability calls the injected GetOrganizationNamespaceAvailabilityFunc or the real version. +func (asc *AppServiceClient) GetOrganizationNamespaceAvailability( + ctx context.Context, in *apppb.GetOrganizationNamespaceAvailabilityRequest, opts ...grpc.CallOption, +) (*apppb.GetOrganizationNamespaceAvailabilityResponse, error) { + if asc.GetOrganizationNamespaceAvailabilityFunc == nil { + return asc.AppServiceClient.GetOrganizationNamespaceAvailability(ctx, in, opts...) + } + return asc.GetOrganizationNamespaceAvailabilityFunc(ctx, in, opts...) +} + +// UpdateOrganization calls the injected UpdateOrganizationFunc or the real version. +func (asc *AppServiceClient) UpdateOrganization( + ctx context.Context, in *apppb.UpdateOrganizationRequest, opts ...grpc.CallOption, +) (*apppb.UpdateOrganizationResponse, error) { + if asc.UpdateOrganizationFunc == nil { + return asc.AppServiceClient.UpdateOrganization(ctx, in, opts...) + } + return asc.UpdateOrganizationFunc(ctx, in, opts...) +} + +// DeleteOrganization calls the injected DeleteOrganizationFunc or the real version. +func (asc *AppServiceClient) DeleteOrganization( + ctx context.Context, in *apppb.DeleteOrganizationRequest, opts ...grpc.CallOption, +) (*apppb.DeleteOrganizationResponse, error) { + if asc.DeleteOrganizationFunc == nil { + return asc.AppServiceClient.DeleteOrganization(ctx, in, opts...) + } + return asc.DeleteOrganizationFunc(ctx, in, opts...) +} + +// ListOrganizationMembers calls the injected ListOrganizationMembersFunc or the real version. +func (asc *AppServiceClient) ListOrganizationMembers( + ctx context.Context, in *apppb.ListOrganizationMembersRequest, opts ...grpc.CallOption, +) (*apppb.ListOrganizationMembersResponse, error) { + if asc.ListOrganizationMembersFunc == nil { + return asc.AppServiceClient.ListOrganizationMembers(ctx, in, opts...) + } + return asc.ListOrganizationMembersFunc(ctx, in, opts...) +} + +// CreateOrganizationInvite calls the injected CreateOrganizationInviteFunc or the real version. +func (asc *AppServiceClient) CreateOrganizationInvite( + ctx context.Context, in *apppb.CreateOrganizationInviteRequest, opts ...grpc.CallOption, +) (*apppb.CreateOrganizationInviteResponse, error) { + if asc.CreateOrganizationInviteFunc == nil { + return asc.AppServiceClient.CreateOrganizationInvite(ctx, in, opts...) + } + return asc.CreateOrganizationInviteFunc(ctx, in, opts...) +} + +// UpdateOrganizationInviteAuthorizations calls the injected UpdateOrganizationInviteAuthorizationsFunc or the real version. +func (asc *AppServiceClient) UpdateOrganizationInviteAuthorizations( + ctx context.Context, in *apppb.UpdateOrganizationInviteAuthorizationsRequest, opts ...grpc.CallOption, +) (*apppb.UpdateOrganizationInviteAuthorizationsResponse, error) { + if asc.UpdateOrganizationInviteAuthorizationsFunc == nil { + return asc.AppServiceClient.UpdateOrganizationInviteAuthorizations(ctx, in, opts...) + } + return asc.UpdateOrganizationInviteAuthorizationsFunc(ctx, in, opts...) +} + +// DeleteOrganizationMember calls the injected DeleteOrganizationMemberFunc or the real version. +func (asc *AppServiceClient) DeleteOrganizationMember( + ctx context.Context, in *apppb.DeleteOrganizationMemberRequest, opts ...grpc.CallOption, +) (*apppb.DeleteOrganizationMemberResponse, error) { + if asc.DeleteOrganizationMemberFunc == nil { + return asc.AppServiceClient.DeleteOrganizationMember(ctx, in, opts...) + } + return asc.DeleteOrganizationMemberFunc(ctx, in, opts...) +} + +// DeleteOrganizationInvite calls the injected DeleteOrganizationInviteFunc or the real version. +func (asc *AppServiceClient) DeleteOrganizationInvite( + ctx context.Context, in *apppb.DeleteOrganizationInviteRequest, opts ...grpc.CallOption, +) (*apppb.DeleteOrganizationInviteResponse, error) { + if asc.DeleteOrganizationInviteFunc == nil { + return asc.AppServiceClient.DeleteOrganizationInvite(ctx, in, opts...) + } + return asc.DeleteOrganizationInviteFunc(ctx, in, opts...) +} + +// ResendOrganizationInvite calls the injected ResendOrganizationInviteFunc or the real version. +func (asc *AppServiceClient) ResendOrganizationInvite( + ctx context.Context, in *apppb.ResendOrganizationInviteRequest, opts ...grpc.CallOption, +) (*apppb.ResendOrganizationInviteResponse, error) { + if asc.ResendOrganizationInviteFunc == nil { + return asc.AppServiceClient.ResendOrganizationInvite(ctx, in, opts...) + } + return asc.ResendOrganizationInviteFunc(ctx, in, opts...) +} + +// EnableBillingService calls the injected EnableBillingServiceFunc or the real version. +func (asc *AppServiceClient) EnableBillingService( + ctx context.Context, in *apppb.EnableBillingServiceRequest, opts ...grpc.CallOption, +) (*apppb.EnableBillingServiceResponse, error) { + if asc.EnableBillingServiceFunc == nil { + return asc.AppServiceClient.EnableBillingService(ctx, in, opts...) + } + return asc.EnableBillingServiceFunc(ctx, in, opts...) +} + +// DisableBillingService calls the injected DisableBillingServiceFunc or the real version. +func (asc *AppServiceClient) DisableBillingService( + ctx context.Context, in *apppb.DisableBillingServiceRequest, opts ...grpc.CallOption, +) (*apppb.DisableBillingServiceResponse, error) { + if asc.DisableBillingServiceFunc == nil { + return asc.AppServiceClient.DisableBillingService(ctx, in, opts...) + } + return asc.DisableBillingServiceFunc(ctx, in, opts...) +} + +// UpdateBillingService calls the injected UpdateBillingServiceFunc or the real version. +func (asc *AppServiceClient) UpdateBillingService( + ctx context.Context, in *apppb.UpdateBillingServiceRequest, opts ...grpc.CallOption, +) (*apppb.UpdateBillingServiceResponse, error) { + if asc.UpdateBillingServiceFunc == nil { + return asc.AppServiceClient.UpdateBillingService(ctx, in, opts...) + } + return asc.UpdateBillingServiceFunc(ctx, in, opts...) +} + +// OrganizationSetSupportEmail calls the injected OrganizationSetSupportEmailFunc or the real version. +func (asc *AppServiceClient) OrganizationSetSupportEmail( + ctx context.Context, in *apppb.OrganizationSetSupportEmailRequest, opts ...grpc.CallOption, +) (*apppb.OrganizationSetSupportEmailResponse, error) { + if asc.OrganizationSetSupportEmailFunc == nil { + return asc.AppServiceClient.OrganizationSetSupportEmail(ctx, in, opts...) + } + return asc.OrganizationSetSupportEmailFunc(ctx, in, opts...) +} + +// OrganizationGetSupportEmail calls the injected OrganizationGetSupportEmailFunc or the real version. +func (asc *AppServiceClient) OrganizationGetSupportEmail( + ctx context.Context, in *apppb.OrganizationGetSupportEmailRequest, opts ...grpc.CallOption, +) (*apppb.OrganizationGetSupportEmailResponse, error) { + if asc.OrganizationGetSupportEmailFunc == nil { + return asc.AppServiceClient.OrganizationGetSupportEmail(ctx, in, opts...) + } + return asc.OrganizationGetSupportEmailFunc(ctx, in, opts...) +} + +// CreateLocation calls the injected CreateLocationFunc or the real version. +func (asc *AppServiceClient) CreateLocation( + ctx context.Context, in *apppb.CreateLocationRequest, opts ...grpc.CallOption, +) (*apppb.CreateLocationResponse, error) { + if asc.CreateLocationFunc == nil { + return asc.AppServiceClient.CreateLocation(ctx, in, opts...) + } + return asc.CreateLocationFunc(ctx, in, opts...) +} + +// GetLocation calls the injected GetLocationFunc or the real version. +func (asc *AppServiceClient) GetLocation( + ctx context.Context, in *apppb.GetLocationRequest, opts ...grpc.CallOption, +) (*apppb.GetLocationResponse, error) { + if asc.GetLocationFunc == nil { + return asc.AppServiceClient.GetLocation(ctx, in, opts...) + } + return asc.GetLocationFunc(ctx, in, opts...) +} + +// UpdateLocation calls the injected UpdateLocationFunc or the real version. +func (asc *AppServiceClient) UpdateLocation( + ctx context.Context, in *apppb.UpdateLocationRequest, opts ...grpc.CallOption, +) (*apppb.UpdateLocationResponse, error) { + if asc.UpdateLocationFunc == nil { + return asc.AppServiceClient.UpdateLocation(ctx, in, opts...) + } + return asc.UpdateLocationFunc(ctx, in, opts...) +} + +// DeleteLocation calls the injected DeleteLocationFunc or the real version. +func (asc *AppServiceClient) DeleteLocation( + ctx context.Context, in *apppb.DeleteLocationRequest, opts ...grpc.CallOption, +) (*apppb.DeleteLocationResponse, error) { + if asc.DeleteLocationFunc == nil { + return asc.AppServiceClient.DeleteLocation(ctx, in, opts...) + } + return asc.DeleteLocationFunc(ctx, in, opts...) +} + // ListLocations calls the injected ListLocationsFunc or the real version. -func (asc *AppServiceClient) ListLocations(ctx context.Context, in *apppb.ListLocationsRequest, - opts ...grpc.CallOption, +func (asc *AppServiceClient) ListLocations( + ctx context.Context, in *apppb.ListLocationsRequest, opts ...grpc.CallOption, ) (*apppb.ListLocationsResponse, error) { if asc.ListLocationsFunc == nil { return asc.AppServiceClient.ListLocations(ctx, in, opts...) @@ -50,59 +417,79 @@ func (asc *AppServiceClient) ListLocations(ctx context.Context, in *apppb.ListLo return asc.ListLocationsFunc(ctx, in, opts...) } -// ListRobots calls the injected ListRobotsFunc or the real version. -func (asc *AppServiceClient) ListRobots(ctx context.Context, in *apppb.ListRobotsRequest, - opts ...grpc.CallOption, -) (*apppb.ListRobotsResponse, error) { - if asc.ListRobotsFunc == nil { - return asc.AppServiceClient.ListRobots(ctx, in, opts...) +// ShareLocation calls the injected ShareLocationFunc or the real version. +func (asc *AppServiceClient) ShareLocation( + ctx context.Context, in *apppb.ShareLocationRequest, opts ...grpc.CallOption, +) (*apppb.ShareLocationResponse, error) { + if asc.ShareLocationFunc == nil { + return asc.AppServiceClient.ShareLocation(ctx, in, opts...) } - return asc.ListRobotsFunc(ctx, in, opts...) + return asc.ShareLocationFunc(ctx, in, opts...) } -// CreateKey calls the injected CreateKeyFunc or the real version. -func (asc *AppServiceClient) CreateKey(ctx context.Context, in *apppb.CreateKeyRequest, - opts ...grpc.CallOption, -) (*apppb.CreateKeyResponse, error) { - if asc.CreateKeyFunc == nil { - return asc.AppServiceClient.CreateKey(ctx, in, opts...) +// UnshareLocation calls the injected UnshareLocationFunc or the real version. +func (asc *AppServiceClient) UnshareLocation( + ctx context.Context, in *apppb.UnshareLocationRequest, opts ...grpc.CallOption, +) (*apppb.UnshareLocationResponse, error) { + if asc.UnshareLocationFunc == nil { + return asc.AppServiceClient.UnshareLocation(ctx, in, opts...) } - return asc.CreateKeyFunc(ctx, in, opts...) + return asc.UnshareLocationFunc(ctx, in, opts...) } -// GetRobotAPIKeys wraps GetRobotAPIKeys. -func (asc *AppServiceClient) GetRobotAPIKeys(ctx context.Context, in *apppb.GetRobotAPIKeysRequest, - opts ...grpc.CallOption, -) (*apppb.GetRobotAPIKeysResponse, error) { - if asc.GetRobotAPIKeysFunc == nil { - return asc.AppServiceClient.GetRobotAPIKeys(ctx, in, opts...) +// LocationAuth calls the injected LocationAuthFunc or the real version. +func (asc *AppServiceClient) LocationAuth( + ctx context.Context, in *apppb.LocationAuthRequest, opts ...grpc.CallOption, +) (*apppb.LocationAuthResponse, error) { + if asc.LocationAuthFunc == nil { + return asc.AppServiceClient.LocationAuth(ctx, in, opts...) } - return asc.GetRobotAPIKeysFunc(ctx, in, opts...) + return asc.LocationAuthFunc(ctx, in, opts...) } -// GetRobotPart wraps GetRobotPart. -func (asc *AppServiceClient) GetRobotPart(ctx context.Context, in *apppb.GetRobotPartRequest, - opts ...grpc.CallOption, -) (*apppb.GetRobotPartResponse, error) { - if asc.GetRobotPartFunc == nil { - return asc.AppServiceClient.GetRobotPart(ctx, in, opts...) +// CreateLocationSecret calls the injected CreateLocationSecretFunc or the real version. +func (asc *AppServiceClient) CreateLocationSecret( + ctx context.Context, in *apppb.CreateLocationSecretRequest, opts ...grpc.CallOption, +) (*apppb.CreateLocationSecretResponse, error) { + if asc.CreateLocationSecretFunc == nil { + return asc.AppServiceClient.CreateLocationSecret(ctx, in, opts...) } - return asc.GetRobotPartFunc(ctx, in, opts...) + return asc.CreateLocationSecretFunc(ctx, in, opts...) } -// UpdateRobotPart wraps UpdateRobotPart. -func (asc *AppServiceClient) UpdateRobotPart(ctx context.Context, in *apppb.UpdateRobotPartRequest, - opts ...grpc.CallOption, -) (*apppb.UpdateRobotPartResponse, error) { - if asc.GetRobotPartFunc == nil { - return asc.AppServiceClient.UpdateRobotPart(ctx, in, opts...) +// DeleteLocationSecret calls the injected DeleteLocationSecretFunc or the real version. +func (asc *AppServiceClient) DeleteLocationSecret( + ctx context.Context, in *apppb.DeleteLocationSecretRequest, opts ...grpc.CallOption, +) (*apppb.DeleteLocationSecretResponse, error) { + if asc.DeleteLocationSecretFunc == nil { + return asc.AppServiceClient.DeleteLocationSecret(ctx, in, opts...) } - return asc.UpdateRobotPartFunc(ctx, in, opts...) + return asc.DeleteLocationSecretFunc(ctx, in, opts...) +} + +// GetRobot calls the injected GetRobotFunc or the real version. +func (asc *AppServiceClient) GetRobot( + ctx context.Context, in *apppb.GetRobotRequest, opts ...grpc.CallOption, +) (*apppb.GetRobotResponse, error) { + if asc.GetRobotFunc == nil { + return asc.AppServiceClient.GetRobot(ctx, in, opts...) + } + return asc.GetRobotFunc(ctx, in, opts...) +} + +// GetRoverRentalRobots calls the injected GetRoverRentalRobotsFunc or the real version. +func (asc *AppServiceClient) GetRoverRentalRobots( + ctx context.Context, in *apppb.GetRoverRentalRobotsRequest, opts ...grpc.CallOption, +) (*apppb.GetRoverRentalRobotsResponse, error) { + if asc.GetRoverRentalRobotsFunc == nil { + return asc.AppServiceClient.GetRoverRentalRobots(ctx, in, opts...) + } + return asc.GetRoverRentalRobotsFunc(ctx, in, opts...) } // GetRobotParts calls the injected GetRobotPartsFunc or the real version. -func (asc *AppServiceClient) GetRobotParts(ctx context.Context, in *apppb.GetRobotPartsRequest, - opts ...grpc.CallOption, +func (asc *AppServiceClient) GetRobotParts( + ctx context.Context, in *apppb.GetRobotPartsRequest, opts ...grpc.CallOption, ) (*apppb.GetRobotPartsResponse, error) { if asc.GetRobotPartsFunc == nil { return asc.AppServiceClient.GetRobotParts(ctx, in, opts...) @@ -110,12 +497,489 @@ func (asc *AppServiceClient) GetRobotParts(ctx context.Context, in *apppb.GetRob return asc.GetRobotPartsFunc(ctx, in, opts...) } +// GetRobotPart calls the injected GetRobotPartFunc or the real version. +func (asc *AppServiceClient) GetRobotPart( + ctx context.Context, in *apppb.GetRobotPartRequest, opts ...grpc.CallOption, +) (*apppb.GetRobotPartResponse, error) { + if asc.GetRobotPartFunc == nil { + return asc.AppServiceClient.GetRobotPart(ctx, in, opts...) + } + return asc.GetRobotPartFunc(ctx, in, opts...) +} + // GetRobotPartLogs calls the injected GetRobotPartLogsFunc or the real version. -func (asc *AppServiceClient) GetRobotPartLogs(ctx context.Context, in *apppb.GetRobotPartLogsRequest, - opts ...grpc.CallOption, +func (asc *AppServiceClient) GetRobotPartLogs( + ctx context.Context, in *apppb.GetRobotPartLogsRequest, opts ...grpc.CallOption, ) (*apppb.GetRobotPartLogsResponse, error) { if asc.GetRobotPartLogsFunc == nil { return asc.AppServiceClient.GetRobotPartLogs(ctx, in, opts...) } return asc.GetRobotPartLogsFunc(ctx, in, opts...) } + +// TailRobotPartLogs calls the injected TailRobotPartLogsFunc or the real version. +func (asc *AppServiceClient) TailRobotPartLogs( + ctx context.Context, in *apppb.TailRobotPartLogsRequest, opts ...grpc.CallOption, +) (apppb.AppService_TailRobotPartLogsClient, error) { + if asc.TailRobotPartLogsFunc == nil { + return asc.AppServiceClient.TailRobotPartLogs(ctx, in, opts...) + } + return asc.TailRobotPartLogsFunc(ctx, in, opts...) +} + +// AppServiceTailRobotPartLogsClient represents a fake instance of a proto AppService_TailRobotPartLogsClient. +type AppServiceTailRobotPartLogsClient struct { + apppb.AppService_TailRobotPartLogsClient + RecvFunc func() (*apppb.TailRobotPartLogsResponse, error) +} + +// Recv calls the injected RecvFunc or the real version. +func (c *AppServiceTailRobotPartLogsClient) Recv() (*apppb.TailRobotPartLogsResponse, error) { + if c.RecvFunc == nil { + return c.AppService_TailRobotPartLogsClient.Recv() + } + return c.RecvFunc() +} + +// GetRobotPartHistory calls the injected GetRobotPartHistoryFunc or the real version. +func (asc *AppServiceClient) GetRobotPartHistory( + ctx context.Context, in *apppb.GetRobotPartHistoryRequest, opts ...grpc.CallOption, +) (*apppb.GetRobotPartHistoryResponse, error) { + if asc.GetRobotPartHistoryFunc == nil { + return asc.AppServiceClient.GetRobotPartHistory(ctx, in, opts...) + } + return asc.GetRobotPartHistoryFunc(ctx, in, opts...) +} + +// UpdateRobotPart calls the injected UpdateRobotPartFunc or the real version. +func (asc *AppServiceClient) UpdateRobotPart( + ctx context.Context, in *apppb.UpdateRobotPartRequest, opts ...grpc.CallOption, +) (*apppb.UpdateRobotPartResponse, error) { + if asc.UpdateRobotPartFunc == nil { + return asc.AppServiceClient.UpdateRobotPart(ctx, in, opts...) + } + return asc.UpdateRobotPartFunc(ctx, in, opts...) +} + +// NewRobotPart calls the injected NewRobotPartFunc or the real version. +func (asc *AppServiceClient) NewRobotPart( + ctx context.Context, in *apppb.NewRobotPartRequest, opts ...grpc.CallOption, +) (*apppb.NewRobotPartResponse, error) { + if asc.NewRobotPartFunc == nil { + return asc.AppServiceClient.NewRobotPart(ctx, in, opts...) + } + return asc.NewRobotPartFunc(ctx, in, opts...) +} + +// DeleteRobotPart calls the injected DeleteRobotPartFunc or the real version. +func (asc *AppServiceClient) DeleteRobotPart( + ctx context.Context, in *apppb.DeleteRobotPartRequest, opts ...grpc.CallOption, +) (*apppb.DeleteRobotPartResponse, error) { + if asc.DeleteRobotPartFunc == nil { + return asc.AppServiceClient.DeleteRobotPart(ctx, in, opts...) + } + return asc.DeleteRobotPartFunc(ctx, in, opts...) +} + +// GetRobotAPIKeys calls the injected GetRobotAPIKeysFunc or the real version. +func (asc *AppServiceClient) GetRobotAPIKeys( + ctx context.Context, in *apppb.GetRobotAPIKeysRequest, opts ...grpc.CallOption, +) (*apppb.GetRobotAPIKeysResponse, error) { + if asc.GetRobotAPIKeysFunc == nil { + return asc.AppServiceClient.GetRobotAPIKeys(ctx, in, opts...) + } + return asc.GetRobotAPIKeysFunc(ctx, in, opts...) +} + +// MarkPartAsMain calls the injected MarkPartAsMainFunc or the real version. +func (asc *AppServiceClient) MarkPartAsMain( + ctx context.Context, in *apppb.MarkPartAsMainRequest, opts ...grpc.CallOption, +) (*apppb.MarkPartAsMainResponse, error) { + if asc.MarkPartAsMainFunc == nil { + return asc.AppServiceClient.MarkPartAsMain(ctx, in, opts...) + } + return asc.MarkPartAsMainFunc(ctx, in, opts...) +} + +// MarkPartForRestart calls the injected MarkPartForRestartFunc or the real version. +func (asc *AppServiceClient) MarkPartForRestart( + ctx context.Context, in *apppb.MarkPartForRestartRequest, opts ...grpc.CallOption, +) (*apppb.MarkPartForRestartResponse, error) { + if asc.MarkPartForRestartFunc == nil { + return asc.AppServiceClient.MarkPartForRestart(ctx, in, opts...) + } + return asc.MarkPartForRestartFunc(ctx, in, opts...) +} + +// CreateRobotPartSecret calls the injected CreateRobotPartSecretFunc or the real version. +func (asc *AppServiceClient) CreateRobotPartSecret( + ctx context.Context, in *apppb.CreateRobotPartSecretRequest, opts ...grpc.CallOption, +) (*apppb.CreateRobotPartSecretResponse, error) { + if asc.CreateRobotPartSecretFunc == nil { + return asc.AppServiceClient.CreateRobotPartSecret(ctx, in, opts...) + } + return asc.CreateRobotPartSecretFunc(ctx, in, opts...) +} + +// DeleteRobotPartSecret calls the injected DeleteRobotPartSecretFunc or the real version. +func (asc *AppServiceClient) DeleteRobotPartSecret( + ctx context.Context, in *apppb.DeleteRobotPartSecretRequest, opts ...grpc.CallOption, +) (*apppb.DeleteRobotPartSecretResponse, error) { + if asc.DeleteRobotPartSecretFunc == nil { + return asc.AppServiceClient.DeleteRobotPartSecret(ctx, in, opts...) + } + return asc.DeleteRobotPartSecretFunc(ctx, in, opts...) +} + +// ListRobots calls the injected ListRobotsFunc or the real version. +func (asc *AppServiceClient) ListRobots( + ctx context.Context, in *apppb.ListRobotsRequest, opts ...grpc.CallOption, +) (*apppb.ListRobotsResponse, error) { + if asc.ListRobotsFunc == nil { + return asc.AppServiceClient.ListRobots(ctx, in, opts...) + } + return asc.ListRobotsFunc(ctx, in, opts...) +} + +// NewRobot calls the injected NewRobotFunc or the real version. +func (asc *AppServiceClient) NewRobot( + ctx context.Context, in *apppb.NewRobotRequest, opts ...grpc.CallOption, +) (*apppb.NewRobotResponse, error) { + if asc.NewRobotFunc == nil { + return asc.AppServiceClient.NewRobot(ctx, in, opts...) + } + return asc.NewRobotFunc(ctx, in, opts...) +} + +// UpdateRobot calls the injected UpdateRobotFunc or the real version. +func (asc *AppServiceClient) UpdateRobot( + ctx context.Context, in *apppb.UpdateRobotRequest, opts ...grpc.CallOption, +) (*apppb.UpdateRobotResponse, error) { + if asc.UpdateRobotFunc == nil { + return asc.AppServiceClient.UpdateRobot(ctx, in, opts...) + } + return asc.UpdateRobotFunc(ctx, in, opts...) +} + +// DeleteRobot calls the injected DeleteRobotFunc or the real version. +func (asc *AppServiceClient) DeleteRobot( + ctx context.Context, in *apppb.DeleteRobotRequest, opts ...grpc.CallOption, +) (*apppb.DeleteRobotResponse, error) { + if asc.DeleteRobotFunc == nil { + return asc.AppServiceClient.DeleteRobot(ctx, in, opts...) + } + return asc.DeleteRobotFunc(ctx, in, opts...) +} + +// ListFragments calls the injected ListFragmentsFunc or the real version. +func (asc *AppServiceClient) ListFragments( + ctx context.Context, in *apppb.ListFragmentsRequest, opts ...grpc.CallOption, +) (*apppb.ListFragmentsResponse, error) { + if asc.ListFragmentsFunc == nil { + return asc.AppServiceClient.ListFragments(ctx, in, opts...) + } + return asc.ListFragmentsFunc(ctx, in, opts...) +} + +// GetFragment calls the injected GetFragmentFunc or the real version. +func (asc *AppServiceClient) GetFragment( + ctx context.Context, in *apppb.GetFragmentRequest, opts ...grpc.CallOption, +) (*apppb.GetFragmentResponse, error) { + if asc.GetFragmentFunc == nil { + return asc.AppServiceClient.GetFragment(ctx, in, opts...) + } + return asc.GetFragmentFunc(ctx, in, opts...) +} + +// CreateFragment calls the injected CreateFragmentFunc or the real version. +func (asc *AppServiceClient) CreateFragment( + ctx context.Context, in *apppb.CreateFragmentRequest, opts ...grpc.CallOption, +) (*apppb.CreateFragmentResponse, error) { + if asc.CreateFragmentFunc == nil { + return asc.AppServiceClient.CreateFragment(ctx, in, opts...) + } + return asc.CreateFragmentFunc(ctx, in, opts...) +} + +// UpdateFragment calls the injected UpdateFragmentFunc or the real version. +func (asc *AppServiceClient) UpdateFragment( + ctx context.Context, in *apppb.UpdateFragmentRequest, opts ...grpc.CallOption, +) (*apppb.UpdateFragmentResponse, error) { + if asc.UpdateFragmentFunc == nil { + return asc.AppServiceClient.UpdateFragment(ctx, in, opts...) + } + return asc.UpdateFragmentFunc(ctx, in, opts...) +} + +// DeleteFragment calls the injected DeleteFragmentFunc or the real version. +func (asc *AppServiceClient) DeleteFragment( + ctx context.Context, in *apppb.DeleteFragmentRequest, opts ...grpc.CallOption, +) (*apppb.DeleteFragmentResponse, error) { + if asc.DeleteFragmentFunc == nil { + return asc.AppServiceClient.DeleteFragment(ctx, in, opts...) + } + return asc.DeleteFragmentFunc(ctx, in, opts...) +} + +// ListMachineFragments calls the injected ListMachineFragmentsFunc or the real version. +func (asc *AppServiceClient) ListMachineFragments( + ctx context.Context, in *apppb.ListMachineFragmentsRequest, opts ...grpc.CallOption, +) (*apppb.ListMachineFragmentsResponse, error) { + if asc.ListMachineFragmentsFunc == nil { + return asc.AppServiceClient.ListMachineFragments(ctx, in, opts...) + } + return asc.ListMachineFragmentsFunc(ctx, in, opts...) +} + +// GetFragmentHistory calls the injected GetFragmentHistoryFunc or the real version. +func (asc *AppServiceClient) GetFragmentHistory( + ctx context.Context, in *apppb.GetFragmentHistoryRequest, opts ...grpc.CallOption, +) (*apppb.GetFragmentHistoryResponse, error) { + if asc.GetFragmentHistoryFunc == nil { + return asc.AppServiceClient.GetFragmentHistory(ctx, in, opts...) + } + return asc.GetFragmentHistoryFunc(ctx, in, opts...) +} + +// AddRole calls the injected AddRoleFunc or the real version. +func (asc *AppServiceClient) AddRole( + ctx context.Context, in *apppb.AddRoleRequest, opts ...grpc.CallOption, +) (*apppb.AddRoleResponse, error) { + if asc.AddRoleFunc == nil { + return asc.AppServiceClient.AddRole(ctx, in, opts...) + } + return asc.AddRoleFunc(ctx, in, opts...) +} + +// RemoveRole calls the injected RemoveRoleFunc or the real version. +func (asc *AppServiceClient) RemoveRole( + ctx context.Context, in *apppb.RemoveRoleRequest, opts ...grpc.CallOption, +) (*apppb.RemoveRoleResponse, error) { + if asc.RemoveRoleFunc == nil { + return asc.AppServiceClient.RemoveRole(ctx, in, opts...) + } + return asc.RemoveRoleFunc(ctx, in, opts...) +} + +// ChangeRole calls the injected ChangeRoleFunc or the real version. +func (asc *AppServiceClient) ChangeRole( + ctx context.Context, in *apppb.ChangeRoleRequest, opts ...grpc.CallOption, +) (*apppb.ChangeRoleResponse, error) { + if asc.ChangeRoleFunc == nil { + return asc.AppServiceClient.ChangeRole(ctx, in, opts...) + } + return asc.ChangeRoleFunc(ctx, in, opts...) +} + +// ListAuthorizations calls the injected ListAuthorizationsFunc or the real version. +func (asc *AppServiceClient) ListAuthorizations( + ctx context.Context, in *apppb.ListAuthorizationsRequest, opts ...grpc.CallOption, +) (*apppb.ListAuthorizationsResponse, error) { + if asc.ListAuthorizationsFunc == nil { + return asc.AppServiceClient.ListAuthorizations(ctx, in, opts...) + } + return asc.ListAuthorizationsFunc(ctx, in, opts...) +} + +// CheckPermissions calls the injected CheckPermissionsFunc or the real version. +func (asc *AppServiceClient) CheckPermissions( + ctx context.Context, in *apppb.CheckPermissionsRequest, opts ...grpc.CallOption, +) (*apppb.CheckPermissionsResponse, error) { + if asc.CheckPermissionsFunc == nil { + return asc.AppServiceClient.CheckPermissions(ctx, in, opts...) + } + return asc.CheckPermissionsFunc(ctx, in, opts...) +} + +// GetRegistryItem calls the injected GetRegistryItemFunc or the real version. +func (asc *AppServiceClient) GetRegistryItem( + ctx context.Context, in *apppb.GetRegistryItemRequest, opts ...grpc.CallOption, +) (*apppb.GetRegistryItemResponse, error) { + if asc.GetRegistryItemFunc == nil { + return asc.AppServiceClient.GetRegistryItem(ctx, in, opts...) + } + return asc.GetRegistryItemFunc(ctx, in, opts...) +} + +// CreateRegistryItem calls the injected CreateRegistryItemFunc or the real version. +func (asc *AppServiceClient) CreateRegistryItem( + ctx context.Context, in *apppb.CreateRegistryItemRequest, opts ...grpc.CallOption, +) (*apppb.CreateRegistryItemResponse, error) { + if asc.CreateRegistryItemFunc == nil { + return asc.AppServiceClient.CreateRegistryItem(ctx, in, opts...) + } + return asc.CreateRegistryItemFunc(ctx, in, opts...) +} + +// UpdateRegistryItem calls the injected UpdateRegistryItemFunc or the real version. +func (asc *AppServiceClient) UpdateRegistryItem( + ctx context.Context, in *apppb.UpdateRegistryItemRequest, opts ...grpc.CallOption, +) (*apppb.UpdateRegistryItemResponse, error) { + if asc.UpdateRegistryItemFunc == nil { + return asc.AppServiceClient.UpdateRegistryItem(ctx, in, opts...) + } + return asc.UpdateRegistryItemFunc(ctx, in, opts...) +} + +// ListRegistryItems calls the injected ListRegistryItemsFunc or the real version. +func (asc *AppServiceClient) ListRegistryItems( + ctx context.Context, in *apppb.ListRegistryItemsRequest, opts ...grpc.CallOption, +) (*apppb.ListRegistryItemsResponse, error) { + if asc.ListRegistryItemsFunc == nil { + return asc.AppServiceClient.ListRegistryItems(ctx, in, opts...) + } + return asc.ListRegistryItemsFunc(ctx, in, opts...) +} + +// DeleteRegistryItem calls the injected DeleteRegistryItemFunc or the real version. +func (asc *AppServiceClient) DeleteRegistryItem( + ctx context.Context, in *apppb.DeleteRegistryItemRequest, opts ...grpc.CallOption, +) (*apppb.DeleteRegistryItemResponse, error) { + if asc.DeleteRegistryItemFunc == nil { + return asc.AppServiceClient.DeleteRegistryItem(ctx, in, opts...) + } + return asc.DeleteRegistryItemFunc(ctx, in, opts...) +} + +// TransferRegistryItem calls the injected TransferRegistryItemFunc or the real version. +func (asc *AppServiceClient) TransferRegistryItem( + ctx context.Context, in *apppb.TransferRegistryItemRequest, opts ...grpc.CallOption, +) (*apppb.TransferRegistryItemResponse, error) { + if asc.TransferRegistryItemFunc == nil { + return asc.AppServiceClient.TransferRegistryItem(ctx, in, opts...) + } + return asc.TransferRegistryItemFunc(ctx, in, opts...) +} + +// CreateModule calls the injected CreateModuleFunc or the real version. +func (asc *AppServiceClient) CreateModule( + ctx context.Context, in *apppb.CreateModuleRequest, opts ...grpc.CallOption, +) (*apppb.CreateModuleResponse, error) { + if asc.CreateModuleFunc == nil { + return asc.AppServiceClient.CreateModule(ctx, in, opts...) + } + return asc.CreateModuleFunc(ctx, in, opts...) +} + +// UpdateModule calls the injected UpdateModuleFunc or the real version. +func (asc *AppServiceClient) UpdateModule( + ctx context.Context, in *apppb.UpdateModuleRequest, opts ...grpc.CallOption, +) (*apppb.UpdateModuleResponse, error) { + if asc.UpdateModuleFunc == nil { + return asc.AppServiceClient.UpdateModule(ctx, in, opts...) + } + return asc.UpdateModuleFunc(ctx, in, opts...) +} + +// UploadModuleFile calls the injected UploadModuleFileFunc or the real version. +func (asc *AppServiceClient) UploadModuleFile( + ctx context.Context, opts ...grpc.CallOption, +) (apppb.AppService_UploadModuleFileClient, error) { + if asc.UploadModuleFileFunc == nil { + return asc.AppServiceClient.UploadModuleFile(ctx, opts...) + } + return asc.UploadModuleFileFunc(ctx, opts...) +} + +// AppServiceUploadModuleFileClient represents a fake instance of a proto AppService_UploadModuleFileClient. +type AppServiceUploadModuleFileClient struct { + apppb.AppService_UploadModuleFileClient + SendFunc func(*apppb.UploadModuleFileRequest) error + CloseAndRecvFunc func() (*apppb.UploadModuleFileResponse, error) +} + +// Send calls the injected SendFunc or the real version. +func (c *AppServiceUploadModuleFileClient) Send(req *apppb.UploadModuleFileRequest) error { + if c.SendFunc == nil { + return c.AppService_UploadModuleFileClient.Send(req) + } + return c.SendFunc(req) +} + +// CloseAndRecv calls the injected CloseAndRecvFunc or the real version. +func (c *AppServiceUploadModuleFileClient) CloseAndRecv() (*apppb.UploadModuleFileResponse, error) { + if c.CloseAndRecvFunc == nil { + return c.AppService_UploadModuleFileClient.CloseAndRecv() + } + return c.CloseAndRecvFunc() +} + +// GetModule calls the injected GetModuleFunc or the real version. +func (asc *AppServiceClient) GetModule( + ctx context.Context, in *apppb.GetModuleRequest, opts ...grpc.CallOption, +) (*apppb.GetModuleResponse, error) { + if asc.GetModuleFunc == nil { + return asc.AppServiceClient.GetModule(ctx, in, opts...) + } + return asc.GetModuleFunc(ctx, in, opts...) +} + +// ListModules calls the injected ListModulesFunc or the real version. +func (asc *AppServiceClient) ListModules( + ctx context.Context, in *apppb.ListModulesRequest, opts ...grpc.CallOption, +) (*apppb.ListModulesResponse, error) { + if asc.ListModulesFunc == nil { + return asc.AppServiceClient.ListModules(ctx, in, opts...) + } + return asc.ListModulesFunc(ctx, in, opts...) +} + +// CreateKey calls the injected CreateKeyFunc or the real version. +func (asc *AppServiceClient) CreateKey( + ctx context.Context, in *apppb.CreateKeyRequest, opts ...grpc.CallOption, +) (*apppb.CreateKeyResponse, error) { + if asc.CreateKeyFunc == nil { + return asc.AppServiceClient.CreateKey(ctx, in, opts...) + } + return asc.CreateKeyFunc(ctx, in, opts...) +} + +// DeleteKey calls the injected DeleteKeyFunc or the real version. +func (asc *AppServiceClient) DeleteKey( + ctx context.Context, in *apppb.DeleteKeyRequest, opts ...grpc.CallOption, +) (*apppb.DeleteKeyResponse, error) { + if asc.DeleteKeyFunc == nil { + return asc.AppServiceClient.DeleteKey(ctx, in, opts...) + } + return asc.DeleteKeyFunc(ctx, in, opts...) +} + +// ListKeys calls the injected ListKeysFunc or the real version. +func (asc *AppServiceClient) ListKeys( + ctx context.Context, in *apppb.ListKeysRequest, opts ...grpc.CallOption, +) (*apppb.ListKeysResponse, error) { + if asc.ListKeysFunc == nil { + return asc.AppServiceClient.ListKeys(ctx, in, opts...) + } + return asc.ListKeysFunc(ctx, in, opts...) +} + +// RenameKey calls the injected RenameKeyFunc or the real version. +func (asc *AppServiceClient) RenameKey( + ctx context.Context, in *apppb.RenameKeyRequest, opts ...grpc.CallOption, +) (*apppb.RenameKeyResponse, error) { + if asc.RenameKeyFunc == nil { + return asc.AppServiceClient.RenameKey(ctx, in, opts...) + } + return asc.RenameKeyFunc(ctx, in, opts...) +} + +// RotateKey calls the injected RotateKeyFunc or the real version. +func (asc *AppServiceClient) RotateKey( + ctx context.Context, in *apppb.RotateKeyRequest, opts ...grpc.CallOption, +) (*apppb.RotateKeyResponse, error) { + if asc.RotateKeyFunc == nil { + return asc.AppServiceClient.RotateKey(ctx, in, opts...) + } + return asc.RotateKeyFunc(ctx, in, opts...) +} + +// CreateKeyFromExistingKeyAuthorizations calls the injected CreateKeyFromExistingKeyAuthorizationsFunc or the real version. +func (asc *AppServiceClient) CreateKeyFromExistingKeyAuthorizations( + ctx context.Context, in *apppb.CreateKeyFromExistingKeyAuthorizationsRequest, opts ...grpc.CallOption, +) (*apppb.CreateKeyFromExistingKeyAuthorizationsResponse, error) { + if asc.CreateKeyFromExistingKeyAuthorizationsFunc == nil { + return asc.AppServiceClient.CreateKeyFromExistingKeyAuthorizations(ctx, in, opts...) + } + return asc.CreateKeyFromExistingKeyAuthorizationsFunc(ctx, in, opts...) +}