RenameUtilTest.java

/*
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v2.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.core.rolling;

import ch.qos.logback.core.Context;
import ch.qos.logback.core.ContextBase;
import ch.qos.logback.core.encoder.EchoEncoder;
import ch.qos.logback.core.encoder.Encoder;
import ch.qos.logback.core.rolling.helper.RenameUtil;
import ch.qos.logback.core.testUtil.CoreTestConstants;
import ch.qos.logback.core.testUtil.RandomUtil;
import ch.qos.logback.core.status.testUtil.StatusChecker;
import ch.qos.logback.core.util.EnvUtil;
import ch.qos.logback.core.util.StatusPrinter;

import ch.qos.logback.core.util.StatusPrinter2;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class RenameUtilTest {

    Encoder<Object> encoder;
    Context context = new ContextBase();
    StatusChecker statusChecker = new StatusChecker(context);
    StatusPrinter2 statusPrinter2 = new StatusPrinter2();

    long currentTime = System.currentTimeMillis();
    int diff = RandomUtil.getPositiveInt();
    protected String randomOutputDirAsStr = CoreTestConstants.OUTPUT_DIR_PREFIX + diff + "/";
    protected File randomOutputDir = new File(randomOutputDirAsStr);

    @BeforeEach
    public void setUp() throws Exception {
        encoder = new EchoEncoder<Object>();
        // if this the fist test run after 'build clean up' then the
        // OUTPUT_DIR_PREFIX might be not yet created
        randomOutputDir.mkdirs();
    }

    @Test
    public void renameToNonExistingDirectory() throws IOException, RolloverFailure {
        RenameUtil renameUtil = new RenameUtil();
        renameUtil.setContext(context);

        int diff2 = RandomUtil.getPositiveInt();
        File fromFile = File.createTempFile("from" + diff, "test", randomOutputDir);

        String randomTARGETDir = CoreTestConstants.OUTPUT_DIR_PREFIX + diff2;

        renameUtil.rename(fromFile.toString(), new File(randomTARGETDir + "/to.test").toString());
        statusPrinter2.printInCaseOfErrorsOrWarnings(context);
        assertTrue(statusChecker.isErrorFree(0));
    }

    @Test // LOGBACK-1054
    public void renameLockedAbstractFile_LOGBACK_1054() throws IOException, RolloverFailure {

        // this tests only works on windows
        if(!EnvUtil.isWindows()) {
            return;
        }

        RenameUtil renameUtil = new RenameUtil();
        renameUtil.setContext(context);

        String abstractFileName = "abstract_pathname-" + diff;

        String src = CoreTestConstants.OUTPUT_DIR_PREFIX + abstractFileName;
        String target = abstractFileName + ".target";

        makeFile(src);

        // open file in a way preventing simple rename in order to force call to
        // areOnDifferentVolumes() method. This only works on Windows

        FileInputStream fis = new FileInputStream(src);
        renameUtil.rename(src, target);
        // release the lock
        fis.close();

        statusPrinter2.print(context);
        assertEquals(0, statusChecker.matchCount("Parent of target file ." + target + ". is null"));
    }

    @Test
    @Disabled
    public void MANUAL_renamingOnDifferentVolumesOnLinux() throws IOException, RolloverFailure {
        RenameUtil renameUtil = new RenameUtil();
        renameUtil.setContext(context);

        String src = "/tmp/ramdisk/foo.txt";
        makeFile(src);

        renameUtil.rename(src, "/tmp/foo" + diff + ".txt");
        statusPrinter2.print(context);
    }

    @Test
    @Disabled
    public void MANUAL_renamingOnDifferentVolumesOnWindows() throws IOException, RolloverFailure {
        RenameUtil renameUtil = new RenameUtil();
        renameUtil.setContext(context);

        String src = "c:/tmp/foo.txt";
        makeFile(src);

        renameUtil.rename(src, "d:/tmp/foo" + diff + ".txt");
        statusPrinter2.print(context);
        assertTrue(statusChecker.isErrorFree(0));
    }

    private void makeFile(String src) throws FileNotFoundException, IOException {

        FileOutputStream fos = new FileOutputStream(src);
        fos.write(("hello" + diff).getBytes());
        fos.close();
    }

}