//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//

// Code generated by MockGen. DO NOT EDIT.
// Source: ./cloudstack/AsyncjobService.go
//
// Generated by this command:
//
//	mockgen -destination=./cloudstack/AsyncjobService_mock.go -package=cloudstack -copyright_file=header.txt -source=./cloudstack/AsyncjobService.go
//

// Package cloudstack is a generated GoMock package.
package cloudstack

import (
	reflect "reflect"

	gomock "go.uber.org/mock/gomock"
)

// MockAsyncjobServiceIface is a mock of AsyncjobServiceIface interface.
type MockAsyncjobServiceIface struct {
	ctrl     *gomock.Controller
	recorder *MockAsyncjobServiceIfaceMockRecorder
	isgomock struct{}
}

// MockAsyncjobServiceIfaceMockRecorder is the mock recorder for MockAsyncjobServiceIface.
type MockAsyncjobServiceIfaceMockRecorder struct {
	mock *MockAsyncjobServiceIface
}

// NewMockAsyncjobServiceIface creates a new mock instance.
func NewMockAsyncjobServiceIface(ctrl *gomock.Controller) *MockAsyncjobServiceIface {
	mock := &MockAsyncjobServiceIface{ctrl: ctrl}
	mock.recorder = &MockAsyncjobServiceIfaceMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAsyncjobServiceIface) EXPECT() *MockAsyncjobServiceIfaceMockRecorder {
	return m.recorder
}

// ListAsyncJobs mocks base method.
func (m *MockAsyncjobServiceIface) ListAsyncJobs(p *ListAsyncJobsParams) (*ListAsyncJobsResponse, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "ListAsyncJobs", p)
	ret0, _ := ret[0].(*ListAsyncJobsResponse)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// ListAsyncJobs indicates an expected call of ListAsyncJobs.
func (mr *MockAsyncjobServiceIfaceMockRecorder) ListAsyncJobs(p any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAsyncJobs", reflect.TypeOf((*MockAsyncjobServiceIface)(nil).ListAsyncJobs), p)
}

// NewListAsyncJobsParams mocks base method.
func (m *MockAsyncjobServiceIface) NewListAsyncJobsParams() *ListAsyncJobsParams {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "NewListAsyncJobsParams")
	ret0, _ := ret[0].(*ListAsyncJobsParams)
	return ret0
}

// NewListAsyncJobsParams indicates an expected call of NewListAsyncJobsParams.
func (mr *MockAsyncjobServiceIfaceMockRecorder) NewListAsyncJobsParams() *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewListAsyncJobsParams", reflect.TypeOf((*MockAsyncjobServiceIface)(nil).NewListAsyncJobsParams))
}

// NewQueryAsyncJobResultParams mocks base method.
func (m *MockAsyncjobServiceIface) NewQueryAsyncJobResultParams(jobid string) *QueryAsyncJobResultParams {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "NewQueryAsyncJobResultParams", jobid)
	ret0, _ := ret[0].(*QueryAsyncJobResultParams)
	return ret0
}

// NewQueryAsyncJobResultParams indicates an expected call of NewQueryAsyncJobResultParams.
func (mr *MockAsyncjobServiceIfaceMockRecorder) NewQueryAsyncJobResultParams(jobid any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewQueryAsyncJobResultParams", reflect.TypeOf((*MockAsyncjobServiceIface)(nil).NewQueryAsyncJobResultParams), jobid)
}

// QueryAsyncJobResult mocks base method.
func (m *MockAsyncjobServiceIface) QueryAsyncJobResult(p *QueryAsyncJobResultParams) (*QueryAsyncJobResultResponse, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "QueryAsyncJobResult", p)
	ret0, _ := ret[0].(*QueryAsyncJobResultResponse)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// QueryAsyncJobResult indicates an expected call of QueryAsyncJobResult.
func (mr *MockAsyncjobServiceIfaceMockRecorder) QueryAsyncJobResult(p any) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryAsyncJobResult", reflect.TypeOf((*MockAsyncjobServiceIface)(nil).QueryAsyncJobResult), p)
}
