b/161473124 Implement traversal for the OpenApi4j Server object

Change-Id: I112b66d810cc22bc6828652bbf63f454c8a1a950
diff --git a/build.gradle b/build.gradle
index dc3dcd7..ea3e4a3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,7 +17,7 @@
 ext.libVersions = [
     // Core Libraries
     "guava": "29.0-jre", // 22 June 2020
-    "guice": "4.2.3", // 22 June 2020,
+    "guice": "4.2.3", // 22 June 2020
 
     // Logging
     "flogger": "0.5.1", // 22 June 2020
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java
index e30e1a2..055b696 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionValidationIntegrator.java
@@ -2,7 +2,7 @@
 
 import com.google.common.collect.ImmutableMap;
 
-class BaseExtensionValidationIntegrator extends ExtensionValidationIntegrator {
+final class BaseExtensionValidationIntegrator extends ExtensionValidationIntegrator {
 
   // TODO(b/161441872): Inject ExtensionValidationIntegrator member dependencies.
 
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java
index a224306..b08fc02 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinator.java
@@ -3,7 +3,7 @@
 import java.util.ArrayDeque;
 
 /** Executes {@linkplain Traversal TraversalCommands} in a depth first (right to left) fashion. */
-class BaseTraversalCoordinator implements TraversalCoordinator {
+final class BaseTraversalCoordinator implements TraversalCoordinator {
 
   private final ArrayDeque<TraversalCommand> stack = new ArrayDeque<>();
 
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java
index 225d327..9685618 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversal.java
@@ -5,7 +5,7 @@
 import org.openapi4j.parser.model.v3.Contact;
 
 /** A {@link Traversal} that traverses a {@link Contact} object. */
-class ContactTraversal extends Traversal<Contact> implements ContactTraversalCommand {
+final class ContactTraversal extends Traversal<Contact> implements ContactTraversalCommand {
 
   @Inject
   ContactTraversal(
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversalCommand.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversalCommand.java
index 23843e4..6ca622b 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversalCommand.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ContactTraversalCommand.java
@@ -1,4 +1,4 @@
 package com.apigee.security.oas.extendedvalidator;
 
-/** A {@link TraversalCommand} marker interface for {@link ContactTraversal}. */
+/** A {@link TraversalCommand} interface for {@link ContactTraversal}. */
 public interface ContactTraversalCommand extends TraversalCommand {}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/DistinctTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/DistinctTraversal.java
new file mode 100644
index 0000000..5faf34a
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/DistinctTraversal.java
@@ -0,0 +1,30 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import org.openapi4j.parser.model.OpenApiSchema;
+
+/**
+ * A {@link Traversal} extension that adds naming capability for {@link OpenApiSchema} objects that
+ * carry a distinct name.
+ */
+abstract class DistinctTraversal<T extends OpenApiSchema> extends Traversal<T> {
+
+  private final String name;
+
+  DistinctTraversal(
+      TraversalCoordinator traversalCoordinator,
+      ExtensionValidationIntegrator extensionValidationIntegrator,
+      TraversalCommandFactory traversalCommandFactory,
+      T openApiSchemaObj,
+      String name) {
+    super(
+        traversalCoordinator,
+        extensionValidationIntegrator,
+        traversalCommandFactory,
+        openApiSchemaObj);
+    this.name = name;
+  }
+
+  protected String getName() {
+    return name;
+  }
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java
index 7d7af1e..7078b7b 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorModule.java
@@ -6,7 +6,7 @@
  * Configures the bindings of inner components to be installed in the {@link
  * ExtendedValidatorMainModule}.
  */
-class ExtendedValidatorModule extends AbstractModule {
+final class ExtendedValidatorModule extends AbstractModule {
 
   @Override
   protected void configure() {
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java
index c595190..0a97951 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java
@@ -7,7 +7,7 @@
  * Module with instructions for instantiating instances of {@link Extension} and building {@link
  * ExtensionFactory}.
  */
-public class ExtensionModule extends AbstractModule {
+final class ExtensionModule extends AbstractModule {
   @Override
   protected void configure() {
     install(
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java
index 504a806..2f1781c 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversal.java
@@ -5,7 +5,7 @@
 import org.openapi4j.parser.model.v3.Info;
 
 /** A {@link Traversal} that traverses an {@link Info} object. */
-class InfoTraversal extends Traversal<Info> implements InfoTraversalCommand {
+final class InfoTraversal extends Traversal<Info> implements InfoTraversalCommand {
 
   @Inject
   InfoTraversal(
@@ -24,8 +24,11 @@
   public void traverse() {
     // TODO(b/161441872): Process extensions.
 
+    // TODO(b/161811574): Add check for Contacts' existence.
     traversalCoordinator.handleTraversalCommand(
         traversalCommandFactory.create(openApiSchemaObj.getContact()));
+
+    // TODO(b/161811574): Add check for License's existence.
     traversalCoordinator.handleTraversalCommand(
         traversalCommandFactory.create(openApiSchemaObj.getLicense()));
   }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversalCommand.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversalCommand.java
index 06a524d..0d65bdf 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversalCommand.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/InfoTraversalCommand.java
@@ -1,4 +1,4 @@
 package com.apigee.security.oas.extendedvalidator;
 
-/** A {@link TraversalCommand} marker interface for {@link InfoTraversal}. */
+/** A {@link TraversalCommand} interface for {@link InfoTraversal}. */
 public interface InfoTraversalCommand extends TraversalCommand {}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java
index 86fae07..ba5722d 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversal.java
@@ -5,7 +5,7 @@
 import org.openapi4j.parser.model.v3.License;
 
 /** A {@link Traversal} that traverses a {@link License} object. */
-class LicenseTraversal extends Traversal<License> implements LicenseTraversalCommand {
+final class LicenseTraversal extends Traversal<License> implements LicenseTraversalCommand {
 
   @Inject
   LicenseTraversal(
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversalCommand.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversalCommand.java
index 7bdef8d..5fac7ee 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversalCommand.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/LicenseTraversalCommand.java
@@ -1,4 +1,4 @@
 package com.apigee.security.oas.extendedvalidator;
 
-/** A {@link TraversalCommand} marker interface for {@link LicenseTraversal}. */
+/** A {@link TraversalCommand} interface for {@link LicenseTraversal}. */
 public interface LicenseTraversalCommand extends TraversalCommand {}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java
index e16e5fb..0138fee 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java
@@ -1,11 +1,12 @@
 package com.apigee.security.oas.extendedvalidator;
 
 import com.google.inject.assistedinject.Assisted;
+import java.util.Optional;
 import javax.inject.Inject;
 import org.openapi4j.parser.model.v3.OpenApi3;
 
 /** A {@link Traversal} that traverses an {@link OpenApi3} object. */
-class OpenApiSpecificationTraversal extends Traversal<OpenApi3>
+final class OpenApiSpecificationTraversal extends Traversal<OpenApi3>
     implements OpenApiSpecificationTraversalCommand {
 
   @Inject
@@ -25,7 +26,24 @@
   public void traverse() {
     // TODO(b/161441872): Process extensions.
 
+    traverseInfo();
+    traverseServers();
+  }
+
+  private void traverseInfo() {
+    // TODO(b/161811574): Add check for Info's existence.
+
     traversalCoordinator.handleTraversalCommand(
         traversalCommandFactory.create(openApiSchemaObj.getInfo()));
   }
+
+  private void traverseServers() {
+    Optional.ofNullable(openApiSchemaObj.getServers())
+        .ifPresent(
+            servers ->
+                servers.forEach(
+                    server ->
+                        traversalCoordinator.handleTraversalCommand(
+                            traversalCommandFactory.create(server))));
+  }
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversal.java
new file mode 100644
index 0000000..36dea34
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversal.java
@@ -0,0 +1,42 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.google.inject.assistedinject.Assisted;
+import java.util.Optional;
+import javax.inject.Inject;
+import org.openapi4j.parser.model.v3.Server;
+
+/** A {@link Traversal} that traverses a {@link Server} object. */
+final class ServerTraversal extends Traversal<Server> implements ServerTraversalCommand {
+
+  @Inject
+  ServerTraversal(
+      TraversalCoordinator traversalCoordinator,
+      ExtensionValidationIntegrator extensionValidationIntegrator,
+      TraversalCommandFactory traversalCommandFactory,
+      @Assisted Server openApiSchemaObj) {
+    super(
+        traversalCoordinator,
+        extensionValidationIntegrator,
+        traversalCommandFactory,
+        openApiSchemaObj);
+  }
+
+  @Override
+  public void traverse() {
+    // TODO(b/161441872): Add call to process extensions.
+
+    traverseServerVariables();
+  }
+
+  private void traverseServerVariables() {
+    Optional.ofNullable(openApiSchemaObj.getVariables())
+        .ifPresent(
+            serverVariables -> {
+              serverVariables.forEach(
+                  (name, serverVariable) -> {
+                    traversalCoordinator.handleTraversalCommand(
+                        traversalCommandFactory.create(serverVariable, name));
+                  });
+            });
+  }
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversalCommand.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversalCommand.java
new file mode 100644
index 0000000..02dd7be
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerTraversalCommand.java
@@ -0,0 +1,4 @@
+package com.apigee.security.oas.extendedvalidator;
+
+/** A {@link TraversalCommand} interface for {@link ServerTraversal}. */
+public interface ServerTraversalCommand extends TraversalCommand {}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversal.java
new file mode 100644
index 0000000..255557c
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversal.java
@@ -0,0 +1,30 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.google.inject.assistedinject.Assisted;
+import javax.inject.Inject;
+import org.openapi4j.parser.model.v3.ServerVariable;
+
+/** A {@link DistinctTraversal} that traverses a {@link ServerVariable} object. */
+final class ServerVariableTraversal extends DistinctTraversal<ServerVariable>
+    implements ServerVariableTraversalCommand {
+
+  @Inject
+  ServerVariableTraversal(
+      TraversalCoordinator traversalCoordinator,
+      ExtensionValidationIntegrator extensionValidationIntegrator,
+      TraversalCommandFactory traversalCommandFactory,
+      @Assisted ServerVariable openApiSchemaObj,
+      @Assisted String name) {
+    super(
+        traversalCoordinator,
+        extensionValidationIntegrator,
+        traversalCommandFactory,
+        openApiSchemaObj,
+        name);
+  }
+
+  @Override
+  public void traverse() {
+    // TODO(b/161441872): Add call to process extensions.
+  }
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversalCommand.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversalCommand.java
new file mode 100644
index 0000000..91d726a
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ServerVariableTraversalCommand.java
@@ -0,0 +1,4 @@
+package com.apigee.security.oas.extendedvalidator;
+
+/** A {@link TraversalCommand} interface for {@link ServerVariableTraversal}. */
+public interface ServerVariableTraversalCommand extends TraversalCommand {}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java
index 88ea292..b742780 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java
@@ -4,6 +4,8 @@
 import org.openapi4j.parser.model.v3.Info;
 import org.openapi4j.parser.model.v3.License;
 import org.openapi4j.parser.model.v3.OpenApi3;
+import org.openapi4j.parser.model.v3.Server;
+import org.openapi4j.parser.model.v3.ServerVariable;
 
 /**
  * Generates {@link TraversalCommand} implementations via Guice's {@link
@@ -18,4 +20,8 @@
   ContactTraversalCommand create(Contact contact);
 
   LicenseTraversalCommand create(License license);
+
+  ServerTraversalCommand create(Server server);
+
+  ServerVariableTraversalCommand create(ServerVariable serverVariable, String name);
 }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java
index 592a57b..8384642 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java
@@ -4,7 +4,7 @@
 import com.google.inject.assistedinject.FactoryModuleBuilder;
 
 /** Configures bindings for {@link TraversalCommandFactory}. */
-public class TraversalCommandFactoryModule extends AbstractModule {
+final class TraversalCommandFactoryModule extends AbstractModule {
   @Override
   protected void configure() {
     install(
@@ -14,6 +14,8 @@
             .implement(InfoTraversalCommand.class, InfoTraversal.class)
             .implement(ContactTraversalCommand.class, ContactTraversal.class)
             .implement(LicenseTraversalCommand.class, LicenseTraversal.class)
+            .implement(ServerTraversalCommand.class, ServerTraversal.class)
+            .implement(ServerVariableTraversalCommand.class, ServerVariableTraversal.class)
             .build(TraversalCommandFactory.class));
   }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinatorTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinatorTest.java
index 2fdd475..4a51d28 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinatorTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseTraversalCoordinatorTest.java
@@ -21,11 +21,11 @@
 
   @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
 
-  @Mock private InfoTraversal infoTraversal;
-  @Mock private InfoTraversal infoTraversalChildOne;
-  @Mock private InfoTraversal infoTraversalChildTwo;
-  @Mock private InfoTraversal infoTraversalChildThree;
-  @Mock private InfoTraversal infoTraversalChildFour;
+  @Mock private InfoTraversalCommand infoTraversal;
+  @Mock private InfoTraversalCommand infoTraversalChildOne;
+  @Mock private InfoTraversalCommand infoTraversalChildTwo;
+  @Mock private InfoTraversalCommand infoTraversalChildThree;
+  @Mock private InfoTraversalCommand infoTraversalChildFour;
 
   private TraversalCoordinator traversalCoordinator;
 
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java
index ccf2e2e..f5cac11 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java
@@ -12,7 +12,7 @@
 
 @RunWith(JUnit4.class)
 public class ExtendedValidatorMainModuleTest {
-  
+
   private Injector injector;
 
   /** Sets up main module {@link Injector}. */
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java
index e6dba27..bafcd85 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/InfoTraversalTest.java
@@ -57,4 +57,7 @@
 
     verify(traversalCoordinator).handleTraversalCommand(any(LicenseTraversal.class));
   }
+
+  // TODO(b/161811574): Add tests for additional nullable children.
+
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java
index ea3eb4d..348e2d4 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java
@@ -1,20 +1,26 @@
 package com.apigee.security.oas.extendedvalidator;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Guice;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.mockito.quality.Strictness;
 import org.openapi4j.parser.model.v3.Info;
 import org.openapi4j.parser.model.v3.OpenApi3;
+import org.openapi4j.parser.model.v3.Server;
 
+@RunWith(JUnit4.class)
 public class OpenApiSpecificationTraversalTest {
 
   @Rule public final MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@@ -24,6 +30,7 @@
   @Mock private OpenApi3 openApiSpec;
 
   private OpenApiSpecificationTraversal openApiSpecificationTraversal;
+  private ImmutableList<Server> servers;
 
   /** Sets up live and mocked instances for testing. */
   @Before
@@ -39,6 +46,9 @@
             traversalCommandFactory,
             openApiSpec);
 
+    servers = ImmutableList.of(new Server(), new Server(), new Server());
+    when(openApiSpec.getServers()).thenReturn(servers);
+
     when(openApiSpec.getInfo()).thenReturn(new Info());
   }
 
@@ -48,4 +58,21 @@
 
     verify(traversalCoordinator).handleTraversalCommand(any(InfoTraversal.class));
   }
+
+  // TODO(b/161811574): Add tests for additional nullable children.
+
+  @Test
+  public void traverse_sendsServerChildrenTraversalsToTraversalCommander() {
+    openApiSpecificationTraversal.traverse();
+
+    verify(traversalCoordinator, times(servers.size()))
+        .handleTraversalCommand(any(ServerTraversalCommand.class));
+  }
+
+  @Test
+  public void traverse_nullServerChildren_doesNotThrowException() {
+    when(openApiSpec.getServers()).thenReturn(null);
+
+    openApiSpecificationTraversal.traverse();
+  }
 }
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ServerTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ServerTraversalTest.java
new file mode 100644
index 0000000..635b3fc
--- /dev/null
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ServerTraversalTest.java
@@ -0,0 +1,69 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Guice;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+import org.openapi4j.parser.model.v3.Server;
+import org.openapi4j.parser.model.v3.ServerVariable;
+
+@RunWith(JUnit4.class)
+public class ServerTraversalTest {
+
+  @Rule public final MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+  @Mock private TraversalCoordinator traversalCoordinator;
+  @Mock private ExtensionValidationIntegrator extensionValidationIntegrator;
+  @Mock private Server server;
+  @Mock private ServerVariable serverVariable;
+
+  private ServerTraversal serverTraversal;
+  private ImmutableMap<String, ServerVariable> serverVariables;
+
+  /** Sets up live and mocked instances for testing. */
+  @Before
+  public void setup() {
+    TraversalCommandFactory traversalCommandFactory =
+        Guice.createInjector(new ExtendedValidatorMainModule())
+            .getInstance(TraversalCommandFactory.class);
+
+    serverTraversal =
+        new ServerTraversal(
+            traversalCoordinator, extensionValidationIntegrator, traversalCommandFactory, server);
+
+    serverVariables =
+        ImmutableMap.of(
+            "serverVariableOne", serverVariable,
+            "ServerVariableTwo", serverVariable,
+            "ServerVariableThree", serverVariable);
+  }
+
+  @Test
+  public void traverse_sendsServerVariableChildrenTraversalsToTraversalCommander() {
+    when(server.getVariables()).thenReturn(serverVariables);
+
+    serverTraversal.traverse();
+
+    verify(traversalCoordinator, times(serverVariables.size()))
+        .handleTraversalCommand(any(ServerVariableTraversal.class));
+  }
+
+  @Test
+  public void traverse_nullServerVariableChildren_doesNotFail() {
+    when(server.getVariables()).thenReturn(null);
+
+    serverTraversal.traverse();
+  }
+}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java
index 2cffc83..9f580b4 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java
@@ -11,6 +11,8 @@
 import org.openapi4j.parser.model.v3.Info;
 import org.openapi4j.parser.model.v3.License;
 import org.openapi4j.parser.model.v3.OpenApi3;
+import org.openapi4j.parser.model.v3.Server;
+import org.openapi4j.parser.model.v3.ServerVariable;
 
 @RunWith(JUnit4.class)
 public class TraversalCommandFactoryTest {
@@ -48,4 +50,18 @@
     assertThat(traversalCommandFactory.create(new License()))
         .isInstanceOf(LicenseTraversalCommand.class);
   }
+
+  @Test
+  public void create_serverObjectPassed_returnsServerTraversalCommand() {
+    assertThat(traversalCommandFactory.create(new Server()))
+        .isInstanceOf(ServerTraversalCommand.class);
+  }
+
+  @Test
+  public void create_nameAndServerVariableObjectPassed_returnsServerVariableTraversalCommand() {
+    ServerVariableTraversalCommand traversal =
+        traversalCommandFactory.create(new ServerVariable(), "serverVariableName");
+
+    assertThat(traversal).isInstanceOf(ServerVariableTraversalCommand.class);
+  }
 }