1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.invoker.shard; 17 18 import com.android.tradefed.error.HarnessRuntimeException; 19 import com.android.tradefed.result.error.InfraErrorIdentifier; 20 21 import com.proto.tradefed.feature.MultiPartResponse; 22 import com.proto.tradefed.feature.PartResponse; 23 24 import java.util.ArrayList; 25 import java.util.List; 26 import java.util.Optional; 27 28 /** 29 * Data-holding class in order to make sending via the feature server easier. 30 * 31 * <p>WARNING: THIS CLASS NEEDS TO BE BACKWARD COMPATIBLE WITH ITSELF AT LEAST 2 WEEKS BACK. IT MUST 32 * MESH WITH THE DEPLOYED VERSION WHICH CAN BE UP TO A COUPLE WEEKS OLD. This is because this class 33 * handles serialization and deserialization for a feature, but it must work with the lab-deployed 34 * version which is going to be an older version of this class. 35 */ 36 public class DynamicShardingConnectionInfoMessage implements IDynamicShardingConnectionInfo { 37 private final String mServerName; 38 private final Integer mServerPort; 39 private final List<String> mAuthScopes; 40 41 public static final String SERVER_NAME_KEY = "server_name"; 42 public static final String SERVER_PORT_KEY = "server_port"; 43 public static final String AUTH_SCOPES_KEY = "auth_scopes"; 44 DynamicShardingConnectionInfoMessage( String serverName, Integer serverPort, List<String> authScopes)45 DynamicShardingConnectionInfoMessage( 46 String serverName, Integer serverPort, List<String> authScopes) { 47 mServerName = serverName; 48 mServerPort = serverPort; 49 mAuthScopes = authScopes; 50 } 51 fromConnectionInfo( IDynamicShardingConnectionInfo info)52 public static DynamicShardingConnectionInfoMessage fromConnectionInfo( 53 IDynamicShardingConnectionInfo info) { 54 return new DynamicShardingConnectionInfoMessage( 55 info.getServerAddress(), info.getServerPort(), info.getAuthScopes()); 56 } 57 fromMultiPartResponse( MultiPartResponse response)58 public static DynamicShardingConnectionInfoMessage fromMultiPartResponse( 59 MultiPartResponse response) { 60 Optional<String> serverName = Optional.empty(); 61 Optional<Integer> serverPort = Optional.empty(); 62 List<String> authScopes = new ArrayList(); 63 64 for (PartResponse part : response.getResponsePartList()) { 65 if (part.getKey().equals(AUTH_SCOPES_KEY)) { 66 authScopes.add(part.getValue()); 67 } 68 if (part.getKey().equals(SERVER_NAME_KEY)) { 69 if (serverName.isPresent()) { 70 throw new HarnessRuntimeException( 71 "Malformed dynamic sharding connection info: server name was specified" 72 + " more than once.", 73 InfraErrorIdentifier.UNDETERMINED); 74 } 75 serverName = Optional.of(part.getValue()); 76 } 77 if (part.getKey().equals(SERVER_PORT_KEY)) { 78 if (serverPort.isPresent()) { 79 throw new HarnessRuntimeException( 80 "Malformed dynamic sharding connection info: server port was specified" 81 + " more than once.", 82 InfraErrorIdentifier.UNDETERMINED); 83 } 84 serverPort = Optional.of(Integer.parseInt(part.getValue())); 85 } 86 } 87 88 if (!serverName.isPresent()) { 89 throw new HarnessRuntimeException( 90 "Malformed dynamic sharding connection info: server name was not specified.", 91 InfraErrorIdentifier.UNDETERMINED); 92 } 93 94 if (!serverPort.isPresent()) { 95 throw new HarnessRuntimeException( 96 "Malformed dynamic sharding connection info: server port was not specified.", 97 InfraErrorIdentifier.UNDETERMINED); 98 } 99 100 return new DynamicShardingConnectionInfoMessage( 101 serverName.get(), serverPort.get(), authScopes); 102 } 103 toResponseBuilder()104 public MultiPartResponse.Builder toResponseBuilder() { 105 MultiPartResponse.Builder builder = MultiPartResponse.newBuilder(); 106 builder.addResponsePart( 107 PartResponse.newBuilder().setKey(SERVER_NAME_KEY).setValue(mServerName)); 108 builder.addResponsePart( 109 PartResponse.newBuilder().setKey(SERVER_PORT_KEY).setValue(mServerPort.toString())); 110 for (String scope : mAuthScopes) { 111 builder.addResponsePart( 112 PartResponse.newBuilder().setKey(AUTH_SCOPES_KEY).setValue(scope)); 113 } 114 115 return builder; 116 } 117 118 @Override getServerAddress()119 public String getServerAddress() { 120 return mServerName; 121 } 122 123 @Override getServerPort()124 public Integer getServerPort() { 125 return mServerPort; 126 } 127 128 @Override getAuthScopes()129 public List<String> getAuthScopes() { 130 return mAuthScopes; 131 } 132 } 133