package jenkins.plugins.nodejs.configfiles;
import static jenkins.plugins.nodejs.NodeJSConstants.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.mockito.Mockito;
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import hudson.util.Secret;
@RunWith(Parameterized.class)
public class RegistryHelperCredentialsTest {
@Parameters(name = "test registries: {0}")
public static Collection<Object[]> data() throws Exception {
Collection<Object[]> dataParameters = new ArrayList<Object[]>();
user = Mockito.mock(StandardUsernamePasswordCredentials.class);
Mockito.when(user.getId()).thenReturn("privateId");
Mockito.when(user.getUsername()).thenReturn("myuser");
Constructor<Secret> c = Secret.class.getDeclaredConstructor(String.class);
c.setAccessible(true);
Secret userSecret = c.newInstance("mypassword");
Mockito.when(((StandardUsernamePasswordCredentials) user).getPassword()).thenReturn(userSecret);
NPMRegistry globalRegistry = new NPMRegistry("https://registry.npmjs.org", null, null);
NPMRegistry proxyRegistry = new NPMRegistry("https://registry.proxy.com", user.getId(), null);
NPMRegistry scopedGlobalRegsitry = new NPMRegistry("https://registry.npmjs.org", null, "@user1 user2");
NPMRegistry organisationRegistry = new NPMRegistry("https://registry.acme.com", user.getId(), "scope1 scope2");
dataParameters.add(new Object[] { "global no auth", new NPMRegistry[] { globalRegistry } });
dataParameters.add(new Object[] { "proxy with auth", new NPMRegistry[] { proxyRegistry } });
dataParameters.add(new Object[] { "global scoped no auth", new NPMRegistry[] { scopedGlobalRegsitry } });
dataParameters.add(new Object[] { "organisation scoped with auth", new NPMRegistry[] { organisationRegistry } });
dataParameters.add(new Object[] { "mix of proxy + global scoped + scped organisation registries",
new NPMRegistry[] { proxyRegistry, scopedGlobalRegsitry, organisationRegistry } });
return dataParameters;
}
private static StandardUsernameCredentials user;
private NPMRegistry[] registries;
private Map<String, StandardUsernameCredentials> resolvedCredentials;
public RegistryHelperCredentialsTest(String testName, NPMRegistry[] registries) {
this.registries = registries;
resolvedCredentials = new HashMap<>();
for (NPMRegistry r : registries) {
if (r.getCredentialsId() != null) {
resolvedCredentials.put(r.getUrl(), user);
}
}
}
@Test
public void test_registry_credentials() throws Exception {
RegistryHelper helper = new RegistryHelper(Arrays.asList(registries));
String content = helper.fillRegistry("", resolvedCredentials);
assertNotNull(content);
Npmrc npmrc = new Npmrc();
npmrc.from(content);
for (NPMRegistry registry : registries) {
if (!registry.isHasScopes()) {
verifyGlobalRegistry(registry, npmrc);
} else {
verifyScopedRegistry(helper, npmrc, registry);
}
}
}
private void verifyScopedRegistry(RegistryHelper helper, Npmrc npmrc, NPMRegistry registry) {
String prefix = helper.calculatePrefix(registry.getUrl());
for (String scope : registry.getScopesAsList()) {
assertFalse("Unexpected value for " + NPM_SETTINGS_AUTH, npmrc.contains(helper.compose(prefix, NPM_SETTINGS_AUTH)));
if (registry.getCredentialsId() != null) {
// test require authentication, by default is false
assertTrue("Unexpected value for " + NPM_SETTINGS_ALWAYS_AUTH, npmrc.getAsBoolean(helper.compose(prefix, NPM_SETTINGS_ALWAYS_AUTH)));
// test credentials fields
assertEquals("Unexpected value for " + NPM_SETTINGS_USER, user.getUsername(), npmrc.get(helper.compose(prefix, NPM_SETTINGS_USER)));
String password = npmrc.get(helper.compose(prefix, NPM_SETTINGS_PASSWORD));
assertNotNull("Unexpected value for " + NPM_SETTINGS_PASSWORD, password);
password = new String(Base64.decodeBase64(password));
assertEquals("Invalid password for scoped registry", password, "mypassword");
}
scope = '@' + scope;
String scopeKey = helper.compose(scope, NPM_SETTINGS_REGISTRY);
// test registry URL entry
assertTrue("Miss registry entry for scope " + scope, npmrc.contains(scopeKey));
assertEquals("Wrong registry URL for scope " + scope, registry.getUrl() + "/", npmrc.get(scopeKey));
}
}
private void verifyGlobalRegistry(NPMRegistry registry, Npmrc npmrc) {
// test require authentication, by default is false
assertEquals("Unexpected value for " + NPM_SETTINGS_ALWAYS_AUTH, registry.getCredentialsId() != null, npmrc.getAsBoolean(NPM_SETTINGS_ALWAYS_AUTH));
if (registry.getCredentialsId() != null) {
// test _auth
String auth = npmrc.get(NPM_SETTINGS_AUTH);
assertNotNull("Unexpected value for " + NPM_SETTINGS_AUTH, npmrc);
auth = new String(Base64.decodeBase64(auth));
assertThat(auth, allOf(startsWith(user.getUsername()), endsWith("mypassword")));
}
// test registry URL entry
assertEquals("Unexpected value for " + NPM_SETTINGS_REGISTRY, registry.getUrl(), npmrc.get(NPM_SETTINGS_REGISTRY));
}
}