require 'helix_web_services_client' require 'uri' require 'P4' require_relative '../../helix_web_services/lib/hws_strings' #------------------------------------------------------------------------------ # Configuration #------------------------------------------------------------------------------ WS_URL = URI(ENV['WS_URL'] || 'http://localhost:9000/') # This is used to prepare a shelved changelist for the 'submit_change' method P4PORT = ENV['P4PORT'] || 'localhost:1666' TMP_FOLDER = '/tmp/clients' DELETE_CLIENT = !ENV.key?('KEEP_WORKSPACES') CHARSET = ENV['P4CHARSET'] || 'auto' JDOE_USER = 'jdoe' JDOE_PASSWORD = 'johndoe1A!' JDOE_USER2 = 'j\doe' JDOE_PASSWORD2 = 'johndoe1A!' SUPER_USER = 'super' SUPER_PASSWORD = 'superuser1A!' DEVICE_SYNC = File.absolute_path('../../../contrib/deviceSync', __FILE__) #------------------------------------------------------------------------------ # Helpers #------------------------------------------------------------------------------ def cloud_test? (ENV['CLOUD_TEST'] || 'false') =~ (/^(true|1|t|yes$)/i) end def client_as_jdoe client = HelixWebServicesClient.new( url: WS_URL, user: 'jdoe', password: 'johndoe1A!', ssl: {verify: false} ) # also set the P4PORT and P4PASSWD headers client.add_setting('P4PORT',P4PORT) client.add_setting('P4PASSWD',client.login(JDOE_USER, JDOE_PASSWORD)) yield client ensure client.close if client end def client_as_super client = HelixWebServicesClient.new( url: WS_URL, user: 'super', password: 'superuser1A!', ssl: {verify: false} ) # also set the P4PORT and P4PASSWD headers client.add_setting('P4PORT',P4PORT) client.add_setting('P4PASSWD',client.login(SUPER_USER, SUPER_PASSWORD)) yield client ensure client.close if client end def client_as_jdoe2 client = HelixWebServicesClient.new( url: WS_URL, user: 'j\doe', password: 'jdoejdoe1A!', ssl: {verify: false} ) yield client ensure client.close if client end def p4_as_jdoe p4 = P4.new # Make P4Ruby only raise exceptions if there are errors. Warnings # (such as 'no such file(s)' don't get the same treatment. p4.exception_level = P4::RAISE_ERRORS p4.port = P4PORT p4.user = JDOE_USER p4.password = JDOE_PASSWORD p4.charset = CHARSET unless CHARSET.nil? || CHARSET == 'none' p4.connect results = p4.run_login('-p') p4.password = results.first yield p4 if block_given? return p4 ensure p4.disconnect if block_given? end def temp_client_as_jdoe(&block) p4_as_jdoe do |p4| unless Dir.exists?(TMP_FOLDER) FileUtils.makedirs(TMP_FOLDER) end name = (0...8).map { (65 + rand(26)).chr }.join root = File.join(TMP_FOLDER, name) Dir.mkdir(root) p4.client = name spec = p4.fetch_client spec._root = root spec._client = name spec._description = 'test client' # When there's one depot, the view generated maps //depot/... //view/... # instead of //depot/... //view/depot/... like it will with multiple depots. if (spec._view.length == 1) spec._view = ["//depot/... //#{name}/depot/..."] end p4.save_client(spec) p4.run_sync('//...') block.call(p4, root) if DELETE_CLIENT p4.user = SUPER_USER p4.password = SUPER_PASSWORD results = p4.run_login('-p') p4.password = results.first p4.run_client('-d', '-f', name) FileUtils.rmtree(root) end end end def p4_as_super p4 = P4.new # Make P4Ruby only raise exceptions if there are errors. Warnings # (such as 'no such file(s)' don't get the same treatment. p4.exception_level = P4::RAISE_ERRORS p4.port = P4PORT p4.user = SUPER_USER p4.password = SUPER_PASSWORD p4.charset = CHARSET unless CHARSET.nil? || CHARSET == 'none' p4.connect results = p4.run_login('-p') p4.password = results.first yield p4 if block_given? return p4 ensure p4.disconnect if block_given? end def temp_client_as_super(&block) p4_as_super do |p4| unless Dir.exists?(TMP_FOLDER) FileUtils.makedirs(TMP_FOLDER) end name = (0...8).map { (65 + rand(26)).chr }.join root = File.join(TMP_FOLDER, name) Dir.mkdir(root) p4.client = name spec = p4.fetch_client spec._root = root spec._client = name spec._description = 'test client' # When there's one depot, the view generated maps //depot/... //view/... # instead of //depot/... //view/depot/... like it will with multiple depots. if (spec._view.length == 1) spec._view = ["//depot/... //#{name}/depot/..."] end p4.save_client(spec) p4.run_sync('//...') keep_client = block.call(p4, root) if keep_client != true && DELETE_CLIENT p4.user = SUPER_USER p4.password = SUPER_PASSWORD results = p4.run_login('-p') p4.password = results.first p4.run_client('-d', '-f', name) FileUtils.rmtree(root) end end end def temp_stream_client_as_jdoe(&block) p4_as_jdoe do |p4| name = (0...8).map { (65 + rand(26)).chr }.join # Create a stream in the stream-test depot stream_spec = p4.fetch_stream("//stream-test/main-#{name}") stream_spec._type = 'mainline' stream_spec._parent = 'none' p4.save_stream(stream_spec) unless Dir.exists?(TMP_FOLDER) FileUtils.makedirs(TMP_FOLDER) end root = File.join(TMP_FOLDER, name) Dir.mkdir(root) p4.client = name spec = p4.fetch_client spec._root = root spec._client = name spec._description = 'test client' spec._view = nil spec._stream = "//stream-test/main-#{name}" p4.save_client(spec) p4.run_sync('//...') block.call(p4, root, "//stream-test/main-#{name}") if DELETE_CLIENT p4.user = SUPER_USER p4.password = SUPER_PASSWORD results = p4.run_login('-p') p4.password = results.first p4.run_client('-d', '-f', name) FileUtils.rmtree(root) end end end def temp_stream_client_as_super(project, &block) p4_as_super do |p4| name = (0...8).map { (65 + rand(26)).chr }.join # Create a stream in the stream-test depot stream_spec = p4.fetch_stream("//#{project}/main") stream_spec._type = 'mainline' stream_spec._parent = 'none' p4.save_stream(stream_spec) unless Dir.exists?(TMP_FOLDER) FileUtils.makedirs(TMP_FOLDER) end root = File.join(TMP_FOLDER, name) Dir.mkdir(root) p4.client = name spec = p4.fetch_client spec._root = root spec._client = name spec._description = 'test client' spec._view = nil spec._stream = "//#{project}/main" p4.save_client(spec) p4.run_sync('//...') keep_client = block.call(p4, root, "//#{project}/main") if keep_client != true && DELETE_CLIENT p4.user = SUPER_USER p4.password = SUPER_PASSWORD results = p4.run_login('-p') p4.password = results.first p4.run_client('-d', '-f', name) FileUtils.rmtree(root) end end end def depot_path_from_name(project_name) cloud_test? ? "//#{project_name}/main" : "//depot/main/#{project_name}" end def root_depot_path_from_name(project_name) cloud_test? ? depot_path_from_name(project_name) : "//depot/main" end def create_cloud_project(project_name) # don't need to do anything for local tests return unless cloud_test? p4_as_super do |p4s| # TODO: don't do it if it already exists # create a depot depot = p4s.fetch_depot(project_name) depot._type = 'stream' p4s.save_depot(depot) stream = p4s.fetch_stream('-t','mainline',"//#{project_name}/main") stream._name = project_name p4s.save_stream(stream) end end def create_stream_client(project, name) # make a client as well p4_as_super do |p4s| client = p4s.fetch_client('-S',"//#{project}/main",name) dir = File.join('/tmp/sync_test/', name) if Dir.exist?(dir) FileUtils.rm_r(dir) end if !Dir.exist?(dir) FileUtils.mkpath(dir) end client._root = dir p4s.save_client(client) return dir end end def p4ticket_from_client(client) client.settings['P4PASSWD'] end # This will create a local "helix sync" client against the project server. # # In general, the depot_path should be underneath the global HVE_PROJECTS_PATH # setting, which should be set for any operation you need. # # @param depot_path Where the Helix Sync project should be located in the p4d instance # @param client HelixWebServicesClient instance # @param p4 The p4 connection we'll use for local operations, will be reconfigured # @return The local directory we've established as the sync client def create_sync_project(project_name, client, p4) depot_path = depot_path_from_name(project_name) root_depot_path = root_depot_path_from_name(project_name) project_id = HWSStrings.component_encode(project_name) root_dir = Dir.mktmpdir('sync_test') client_info = client.create_helix_sync_device_client(project_id, 'test-machine', root_dir) create_p4config(root_dir, client.user, p4ticket_from_client(client), client_info.client) p4.client = client_info.client sync_output = p4.run_sync("#{depot_path}/...") puts("sync_output #{sync_output}") [root_dir, client_info.client, depot_path, root_depot_path] end def create_p4config(root_dir, user, ticket, client_name) p4config_path = File.join(root_dir, '.p4config') puts "Creating .p4config file in #{root_dir}" IO.write(p4config_path, <<-END.gsub(/^[ ]{8}/, '') P4PORT=#{P4PORT} P4CLIENT=#{client_name} P4PASSWD=#{ticket} P4USER=#{user} END ) end # Launches the device sync application which should set up the pending changelist def run_device_sync(project_name, root_dir, client, device_client) project_id = HWSStrings.component_encode(project_name) client_info = client.create_helix_sync_shelf_client(project_id) shelf_client = client_info.client puts "Client info is #{client_info.inspect}, shelf info is #{shelf_client.inspect}" # Run with SHELF_CLIENT in root direcotry Dir.chdir(root_dir) { ok = system("P4CONFIG=.p4config SHELF_CLIENT=#{shelf_client} P4CLIENT=#{device_client} #{DEVICE_SYNC}") fail 'deviceSync failed' unless ok } end def upload_test_file(project, file_path, content) if !cloud_test? # use the /p4/... api for classic depots client_as_super do |cs| cs.upload_file({DepotFile: depot_path_from_name(project) + '/' + file_path, 'Content': content}) end else dir = create_stream_client(project, "upload_test_file_#{project}") path = File.join(dir, file_path) IO.write(path, content) p4_as_super do |p4s| p4s.client = "upload_test_file_#{project}" p4s.run_add(path) p4s.run_submit('-d', "Upload test file for #{project} : #{file_path}") end end end def delete_test_file(project, file) if !cloud_test? temp_client_as_super do |p4s| r = p4s.run_delete("#{depot_path_from_name(project)}/#{file}") puts "remove from shelf delete: #{r}" r = p4s.run_submit('-d', "deleting #{file}") puts "remove from shelf submit: #{r}" end else temp_stream_client_as_super(project) do |p4s| r = p4s.run_delete("#{depot_path_from_name(project)}/#{file}") puts "remove from shelf delete: #{r}" r = p4s.run_submit('-d', "deleting #{file}") puts "remove from shelf submit: #{r}" end end end def edit_and_lock(project, file) if !cloud_test? temp_client_as_super do |p4s| edit_results = p4s.run_edit("#{depot_path_from_name(project)}/#{file}") puts "edit_results #{edit_results}" lock_results = p4s.run_lock("#{depot_path_from_name(project)}/#{file}") puts "lock_results #{lock_results}" true end else temp_stream_client_as_super(project) do |p4s| edit_results = p4s.run_edit("#{depot_path_from_name(project)}/#{file}") puts "edit_results #{edit_results}" lock_results = p4s.run_lock("#{depot_path_from_name(project)}/#{file}") puts "lock_results #{lock_results}" true end end end def create_new_file_under(dir) randstr = (0...8).map { (65 + rand(26)).chr }.join file_name = "test_#{randstr}" path = File.join(dir, file_name) IO.write(path, randstr) file_name end