testcrashapi.java

来自「非常棒的java数据库」· Java 代码 · 共 428 行 · 第 1/2 页

JAVA
428
字号
/*
 * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
 * (license2)
 * Initial Developer: H2 Group
 */
package org.h2.test.synth;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.BatchUpdateException;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.jdbc.JdbcConnection;
import org.h2.test.TestAll;
import org.h2.test.TestBase;
import org.h2.test.db.TestScript;
import org.h2.test.synth.sql.RandomGen;
import org.h2.util.RandomUtils;

/**
 * A test that calls random methods with random parameters from JDBC objects.
 * This is sometimes called 'Fuzz Testing'.
 */
public class TestCrashAPI extends TestBase {
    public static final Class[] INTERFACES = { Connection.class, PreparedStatement.class, Statement.class,
            ResultSet.class, ResultSetMetaData.class, Savepoint.class,
            ParameterMetaData.class, Clob.class, Blob.class, Array.class, CallableStatement.class };
    private ArrayList objects = new ArrayList();
    private HashMap classMethods = new HashMap();
    private RandomGen random = new RandomGen(null);
    private ArrayList statements = new ArrayList();
    private int openCount;
    private long callCount;
    private static final String DIR = "synth";

    private void deleteDb() {
        try {
            deleteDb(baseDir + "/" + DIR, null);
        } catch (Exception e) {
            // ignore
        }
    }

    private Connection getConnection(int seed, boolean delete) throws Exception {
        openCount++;
        if (delete) {
            deleteDb();
        }
        // can not use FILE_LOCK=NO, otherwise something could be written into
        // the database in the finalize method
        String add = ""; // ";STORAGE=TEXT";

//         int testing;
        // add = ";STORAGE=TEXT";
//        if(openCount >= 32) {
//            int test;
//            Runtime.getRuntime().halt(0);
//            System.exit(1);
//        }
        // add = ";LOG=2";
        // System.out.println("now open " + openCount);
        // add += ";TRACE_LEVEL_FILE=3";
        // config.logMode = 2;
        // }

        String url = getURL(DIR + "/crashApi" + seed, true) + add;
        
//        int test;
//        url += ";DB_CLOSE_ON_EXIT=FALSE";
//      int test;
//      url += ";TRACE_LEVEL_FILE=3";

        Connection conn = null;
        // System.gc();
        conn = DriverManager.getConnection(url, "sa", "");
        int len = random.getInt(50);
        int start = random.getInt(statements.size() - len);
        int end = start + len;
        Statement stat = conn.createStatement();
        stat.execute("SET LOCK_TIMEOUT 10");
        stat.execute("SET WRITE_DELAY 0");
        if (random.nextBoolean()) {
            if (random.nextBoolean()) {
                double g = random.nextGaussian();
                int size = (int) Math.abs(10000 * g * g);
                stat.execute("SET CACHE_SIZE " + size);
            } else {
                stat.execute("SET CACHE_SIZE 0");
            }
        }
        stat.execute("SCRIPT NOPASSWORDS NOSETTINGS");
        for (int i = start; i < end && i < statements.size(); i++) {
            try {
                stat.execute("SELECT * FROM TEST WHERE ID=1");
            } catch (Throwable t) {
                printIfBad(seed, -i, -1, t);
            }
            try {
                stat.execute("SELECT * FROM TEST WHERE ID=1 OR ID=1");
            } catch (Throwable t) {
                printIfBad(seed, -i, -1, t);
            }

            String sql = (String) statements.get(i);
            try {
//                if(openCount == 32) {
//                    int test;
//                    System.out.println("stop!");
//                }
                stat.execute(sql);
            } catch (Throwable t) {
                printIfBad(seed, -i, -1, t);
            }
        }
        if (random.nextBoolean()) {
            try {
                conn.commit();
            } catch (Throwable t) {
                printIfBad(seed, 0, -1, t);
            }
        }
        return conn;
    }

    private void testOne(int seed) throws Exception {
        printTime("seed: " + seed);
        callCount = 0;
        openCount = 0;
        random = new RandomGen(null);
        random.setSeed(seed);
        Connection c1 = getConnection(seed, true);
        Connection conn = null;
        for (int i = 0; i < 2000; i++) {
            // if(i % 10 == 0) {
            // for(int j=0; j<objects.size(); j++) {
            // System.out.print(objects.get(j));
            // System.out.print(" ");
            // }
            // System.out.println();
            // Thread.sleep(1);
            // }

            if (objects.size() == 0) {
                try {
                    conn = getConnection(seed, false);
                } catch (SQLException e) {
                    if (e.getSQLState().equals("08004")) {
                        // Wrong user/password [08004]
                        try {
                            c1.createStatement().execute("SET PASSWORD ''");
                        } catch (Throwable t) {
                            // power off or so
                            break;
                        }
                        try {
                            conn = getConnection(seed, false);
                        } catch (Throwable t) {
                            printIfBad(seed, -i, -1, t);
                        }
                    } else if (e.getSQLState().equals("90098")) {
                        // The database has been closed
                        break;
                    } else {
                        printIfBad(seed, -i, -1, e);
                    }
                }
                objects.add(conn);
            }
            int objectId = random.getInt(objects.size());
            if (random.getBoolean(1)) {
                objects.remove(objectId);
                continue;
            }
            if (random.getInt(2000) == 0 && conn != null) {
                ((JdbcConnection) conn).setPowerOffCount(random.getInt(50));
            }
            Object o = objects.get(objectId);
            if (o == null) {
                objects.remove(objectId);
                continue;
            }
            Class in = getJdbcInterface(o);
            ArrayList methods = (ArrayList) classMethods.get(in);
            Method m = (Method) methods.get(random.getInt(methods.size()));
            Object o2 = callRandom(seed, i, objectId, o, m);
            if (o2 != null) {
                objects.add(o2);
            }
        }
        try {
            if (conn != null) {
                conn.close();
            }
            c1.close();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?