/** * The MIT License * * Copyright (c) 2007-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt, * Henrik Lynggaard, Peter Liljenberg, Andrew Bayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package hudson.plugins.clearcase; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasItemInArray; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import hudson.FilePath; import hudson.Launcher; import hudson.model.TaskListener; import hudson.plugins.clearcase.ClearTool.SetcsOption; import hudson.util.VariableResolver; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.Reader; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.List; import java.util.Locale; import java.util.TimeZone; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.legacy.ClassImposteriser; import org.junit.After; import org.junit.Before; import org.junit.Test; public class ClearToolExecTest extends AbstractWorkspaceTest { private Mockery context; private Mockery classContext; private ClearToolExec clearToolExec; private ClearToolLauncher ccLauncher; private TaskListener listener; private Launcher launcher; private VariableResolver<String> resolver; @Before public void setUp() throws Exception { createWorkspace(); context = new JUnit4Mockery(); classContext = new JUnit4Mockery() { { setImposteriser(ClassImposteriser.INSTANCE); } }; ccLauncher = context.mock(ClearToolLauncher.class); clearToolExec = new ClearToolImpl(ccLauncher); launcher = classContext.mock(Launcher.class); listener = context.mock(TaskListener.class); resolver = context.mock(VariableResolver.class); } @After public void tearDown() throws Exception { deleteWorkspace(); } @Test public void testListViews() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run(with(equal(new String[] { "lsview" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-lsview-1.log")), returnValue(Boolean.TRUE))); } }); List<String> views = clearToolExec.lsview(false); assertEquals("The view list should contain 4 items", 4, views.size()); assertEquals("The first view name is incorrect", "qaaaabbb_R3A_view", views.get(0)); assertEquals("The second view name is incorrect", "qccccddd_view", views.get(1)); assertEquals("The third view name is incorrect", "qeeefff_view", views.get(2)); assertEquals("The fourth view name is incorrect", "qeeefff_HUDSON_SHORT_CS_TEST", views.get(3)); } @Test public void testListActiveDynamicViews() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run(with(equal(new String[] { "lsview" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-lsview-1.log")), returnValue(Boolean.TRUE))); } }); List<String> views = clearToolExec.lsview(true); assertEquals("The view list should contain 1 item", 1, views.size()); assertEquals("The third view name is incorrect", "qeeefff_view", views.get(0)); } @Test public void testListVobs() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run(with(equal(new String[] { "lsvob" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-lsvob-1.log")), returnValue(Boolean.TRUE))); } }); List<String> vobs = clearToolExec.lsvob(false); assertEquals("The vob list should contain 6 items", 6, vobs.size()); assertEquals("The first vob name is incorrect", "demo", vobs.get(0)); assertEquals("The second vob name is incorrect", "pvoba", vobs.get(1)); assertEquals("The third vob name is incorrect", "doc", vobs.get(2)); assertEquals("The fourth vob name is incorrect", "demoa", vobs.get(3)); assertEquals("The fifth vob name is incorrect", "pvob", vobs.get(4)); assertEquals("The sixth vob name is incorrect", "bugvob", vobs.get(5)); } @Test public void testListVobsMounted() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run(with(equal(new String[] { "lsvob" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-lsvob-1.log")), returnValue(Boolean.TRUE))); } }); List<String> vobs = clearToolExec.lsvob(true); assertEquals("The vob list should contain 3 items", 3, vobs.size()); assertEquals("The first vob name is incorrect", "demo", vobs.get(0)); assertEquals("The second vob name is incorrect", "demoa", vobs.get(1)); assertEquals("The third vob name is incorrect", "pvob", vobs.get(2)); } @Test public void testLshistory() throws Exception { workspace.child("viewName").mkdirs(); final Calendar mockedCalendar = Calendar.getInstance(); mockedCalendar.set(2007, 10, 18, 15, 05, 25); SimpleDateFormat formatter = new SimpleDateFormat("d-MMM-yy.HH:mm:ss'UTC'+0000", Locale.US); formatter.setTimeZone(TimeZone.getTimeZone("UTC")); final String formattedDate = formatter.format(mockedCalendar.getTime()).toLowerCase(); context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); allowing(ccLauncher).getLauncher(); will(returnValue(new Launcher.LocalLauncher(null))); one(ccLauncher).run( with(equal(new String[] { "lshistory", "-all", "-since", formattedDate, "-fmt", "FORMAT", "-branch", "brtype:branch", "-nco", "vob1", "vob2", "\"vob 3\"" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNonNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-lshistory-1.log")), returnValue(Boolean.TRUE))); } }); Reader reader = clearToolExec.lshistory("FORMAT", mockedCalendar.getTime(), "viewName","branch", new String[]{ "vob1", "vob2\n", "vob 3"}); assertNotNull("Returned console reader can not be null", reader); } @Test public void testMkbl() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run( with(equal(new String[] { "mkbl", "-comment", "comment", "-incremental", "-view", "viewTag", "myBl" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(any(FilePath.class))); will(doAll( new StreamCopyAction(2, ClearToolExecTest.class .getResourceAsStream("ct-mkbl-1.log")), returnValue(Boolean.TRUE))); } }); List<Baseline> baselines = clearToolExec.mkbl("myBl", "viewTag", "comment", false, false, null, null, null); assertEquals(1, baselines.size()); Baseline baseline = baselines.get(0); assertEquals("mybl", baseline.getBaselineName()); assertEquals("mycomponent", baseline.getComponentName()); } @Test public void testLsHistoryBranchNotFound() throws Exception { workspace.child("viewName").mkdirs(); final Calendar mockedCalendar = Calendar.getInstance(); mockedCalendar.set(2007, 10, 18, 15, 05, 25); SimpleDateFormat formatter = new SimpleDateFormat("d-MMM-yy.HH:mm:ss'UTC'+0000", Locale.US); formatter.setTimeZone(TimeZone.getTimeZone("UTC")); final String formattedDate = formatter.format(mockedCalendar.getTime()).toLowerCase(); context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); allowing(ccLauncher).getLauncher(); will(returnValue(new Launcher.LocalLauncher(null))); one(ccLauncher).run( with(equal(new String[] { "lshistory", "-all", "-since", formattedDate, "-fmt", "FORMAT", "-branch", "brtype:branch", "-nco", "vob1", "vob2", "\"vob 3\"" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNonNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-lshistory-1.log")), throwException(new IOException()))); } }); Reader reader = clearToolExec.lshistory("FORMAT", mockedCalendar.getTime(), "viewName","branch", new String[]{ "vob1", "vob2\n", "vob 3"}); assertNotNull("Returned console reader cannot be null", reader); } @Test public void testCatConfigSpec() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run(with(equal(new String[] { "catcs", "-tag", "viewname" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-catcs-1.log")), returnValue(Boolean.TRUE))); } }); String configSpec = clearToolExec.catcs("viewname"); assertEquals("The config spec was not correct", "element * CHECKEDOUT\nelement * ...\\rel2_bugfix\\LATEST\nelement * \\main\\LATEST -mkbranch rel2_bugfix", configSpec); } @Test public void testRemoveView() throws Exception { context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).run( with(equal(new String[] { "rmview", "-force", "viewName" })), with(aNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.rmview("viewName"); } @Test public void testForcedRemoveView() throws Exception { workspace.child("viewName").mkdirs(); context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).run( with(equal(new String[] { "rmview", "-force", "viewName" })), with(aNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); one(ccLauncher).getListener(); will(returnValue(listener)); one(listener).getLogger(); will(returnValue(new PrintStream(new ByteArrayOutputStream()))); } }); clearToolExec.rmview("viewName"); assertFalse("View folder still exists", workspace.child("viewName") .exists()); } @Test public void testRmTag() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run(with(equal(new String[] {"rmtag", "-view", "myViewTag"})), with(any(InputStream.class)), with(any(OutputStream.class)), with(any(FilePath.class))); } }); clearToolExec.rmtag("myViewTag"); } @Test public void testUpdate() throws Exception { context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).run( with(equal(new String[] { "update", "-force", "-overwrite", "-log", "NUL" })), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.update("viewName", null); } @Test public void testSetcsCurrent() throws Exception { context.checking(new Expectations() { { allowing(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).run( with(equal(new String[] { "setcs", "-current" })), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.setcs("viewName", SetcsOption.CURRENT, null); } @Test(expected=IOException.class) public void testUpdateBlocked() throws Exception { context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).run( with(equal(new String[] { "update", "-force", "-overwrite", "-log", "NUL"})), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(doAll(new StreamCopyAction(2, this.getClass().getResourceAsStream("ct-update-2.log")), returnValue(Boolean.TRUE))); } }); clearToolExec.update("viewName", null); } @Test public void testSetcs() throws Exception { context.checking(new Expectations() { { allowing(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).getLauncher(); will(returnValue(launcher)); one(ccLauncher).run( with(allOf(hasItemInArray("setcs"), hasItemInArray("-tag"), hasItemInArray("viewTag"))), with(any(InputStream.class)), with(any(OutputStream.class)), with(any(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); classContext.checking(new Expectations() { { one(launcher).isUnix(); will(returnValue(true)); } }); clearToolExec.setcsTag("viewTag", SetcsOption.CONFIGSPEC, "configspec"); } @Test(expected=IOException.class) public void testSetcsCurrentBlocked() throws Exception { context.checking(new Expectations() { { allowing(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).run( with(equal(new String[] { "setcs", "-current" })), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(doAll(new StreamCopyAction(2, this.getClass().getResourceAsStream("ct-update-2.log")), returnValue(Boolean.TRUE))); } }); clearToolExec.setcs("viewName", SetcsOption.CURRENT, null); } @Test public void testUpdateWithLoadRulesWindows() throws Exception { classContext.checking(new Expectations() { { allowing(launcher).isUnix(); will(returnValue(false)); } }); context.checking(new Expectations() { { allowing(ccLauncher).getLauncher(); will(returnValue(launcher)); one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher) .run( with(equal(new String[] { "update", "-force", "-overwrite", "-log", "NUL", "-add_loadrules", "more_load_rules" })), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.update("viewName", new String[] {"\\more_load_rules"}); } @Test public void testUpdateWithLoadRules() throws Exception { classContext.checking(new Expectations() { { allowing(launcher).isUnix(); will(returnValue(true)); } }); context.checking(new Expectations() { { allowing(ccLauncher).getLauncher(); will(returnValue(launcher)); one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher) .run( with(equal(new String[] { "update", "-force", "-overwrite", "-log", "NUL", "-add_loadrules", "more_load_rules" })), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.update("viewName", new String[] {"/more_load_rules"}); } @Test public void testUpdateWithLoadRulesWithSpace() throws Exception { classContext.checking(new Expectations() { { allowing(launcher).isUnix(); will(returnValue(true)); } }); context.checking(new Expectations() { { allowing(ccLauncher).getLauncher(); will(returnValue(launcher)); one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher) .run( with(equal(new String[] { "update", "-force", "-overwrite", "-log", "NUL", "-add_loadrules", "\"more load_rules\"" })), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.update("viewName", new String[] {"/more load_rules"}); } @Test public void testUpdateWithLoadRulesWithSpaceWin() throws Exception { classContext.checking(new Expectations() { { allowing(launcher).isUnix(); will(returnValue(false)); } }); context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); allowing(ccLauncher).getLauncher(); will(returnValue(launcher)); one(ccLauncher) .run( with(equal(new String[] { "update", "-force", "-overwrite", "-log", "NUL", "-add_loadrules", "\"more load_rules\"" })), with(aNonNull(InputStream.class)), with(aNonNull(OutputStream.class)), with(aNonNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.update("viewName", new String[] {"\\more load_rules"}); } @Test public void testCreateView() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run( with(equal(new String[] { "mkview", "-snapshot", "-tag", "viewName", "viewpath" })), with(aNull(InputStream.class)), with(aNull(OutputStream.class)), with(aNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.mkview("viewpath", "viewName", null); } @Test public void testCreateViewWithStream() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run( with(equal(new String[] { "mkview", "-snapshot", "-stream", "streamSelector", "-tag", "viewName", "viewpath" })), with(aNull(InputStream.class)), with(aNull(OutputStream.class)), with(aNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec.mkview("viewpath", "viewName", "streamSelector"); } @Test public void testCreateViewExtraParams() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run( with(equal(new String[] { "mkview", "-snapshot", "-tag", "viewName", "-anextraparam", "-anotherparam", "viewpath" })), with(aNull(InputStream.class)), with(aNull(OutputStream.class)), with(aNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec = new ClearToolSnapshot(resolver, ccLauncher, "-anextraparam -anotherparam"); clearToolExec.mkview("viewpath", "viewName", null); } @Test public void testCreateUcmViewWithOptionalParams() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run( with(equal(new String[] { "mkview", "-snapshot", "-stream", "streamSelector", "-tag", "viewName", "-anextraparam", "-anotherparam", "viewpath" })), with(aNull(InputStream.class)), with(aNull(OutputStream.class)), with(aNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); clearToolExec = new ClearToolSnapshot(resolver, ccLauncher, "-anextraparam -anotherparam"); clearToolExec.mkview("viewpath", "viewName", "streamSelector"); } @Test public void testCreateViewExtraParamsEvaluated() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run( with(equal(new String[] { "mkview", "-snapshot", "-tag", "viewName", "-anextraparam", "Test", "viewpath" })), with(aNull(InputStream.class)), with(aNull(OutputStream.class)), with(aNull(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); context.checking(new Expectations() { { atLeast(1).of(resolver).resolve("COMPUTERNAME"); will(returnValue("Test")); } }); clearToolExec = new ClearToolSnapshot(resolver, ccLauncher, "-anextraparam $COMPUTERNAME"); clearToolExec.mkview("viewpath", "viewName", null); } @Test public void testDescribe() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run(with(equal(new String[] { "desc", "-fmt", "format", "stream:stream_selector@\\a_vob" })), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), with(aNull(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-desc-1.log")), returnValue(Boolean.TRUE))); } }); Reader reader = clearToolExec.describe("format", "stream:stream_selector@\\a_vob"); assertNotNull("Returned console reader cannot be null", reader); } @Test public void assertLsactivityReturnsReader() throws Exception { workspace.child("viewName").mkdirs(); context.checking(new Expectations() { { one(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).run( with(equal(new String[] { "lsactivity", "-fmt", "ACTIVITY_FORMAT", "ACTIVITY@VOB"})), (InputStream) with(anything()), (OutputStream) with(an(OutputStream.class)), (FilePath) with(an(FilePath.class))); will(doAll(new StreamCopyAction(2, ClearToolExecTest.class.getResourceAsStream("ct-lsactivity-1.log")), returnValue(Boolean.TRUE))); } }); Reader reader = clearToolExec.lsactivity("ACTIVITY@VOB", "ACTIVITY_FORMAT","VIEW_NAME"); assertNotNull("Returned console reader can not be null", reader); } @Test public void testStartview() throws Exception { context.checking(new Expectations() { { one(ccLauncher).run( with(allOf(hasItemInArray("startview"), hasItemInArray("viewName"))), with(aNull(InputStream.class)), with(aNull(OutputStream.class)), with(aNull(FilePath.class))); } }); clearToolExec.startView("viewName"); } /** * Make sure that if we call setcs with a null or empty string for the config spec, * we get a call to cleartool setcs -current. */ @Test public void testSetcsTag() throws Exception { context.checking(new Expectations() { { allowing(ccLauncher).getWorkspace(); will(returnValue(workspace)); one(ccLauncher).getLauncher(); will(returnValue(launcher)); one(ccLauncher).run( with(allOf(hasItemInArray("setcs"), hasItemInArray("-tag"), hasItemInArray("viewName"), hasItemInArray("-current"))), with(any(InputStream.class)), with(any(OutputStream.class)), with(any(FilePath.class))); will(returnValue(Boolean.TRUE)); } }); classContext.checking(new Expectations() { { one(launcher).isUnix(); will(returnValue(true)); } }); clearToolExec.setcsTag("viewName", SetcsOption.CURRENT, null); } /** * Simple impl of ClearToolExec to help testing the methods in the class */ private static class ClearToolImpl extends ClearToolExec { public ClearToolImpl(ClearToolLauncher launcher) { super(null, launcher, null); } @Override protected FilePath getRootViewPath(ClearToolLauncher launcher) { return launcher.getWorkspace(); } } }