2009-02-25 16:32:09 +08:00
|
|
|
#!/bin/sh
|
|
|
|
|
2009-10-31 08:47:47 +08:00
|
|
|
test_description='test dumb fetching over http via static file'
|
2009-02-25 16:32:09 +08:00
|
|
|
. ./test-lib.sh
|
|
|
|
|
|
|
|
if test -n "$NO_CURL"; then
|
2010-06-25 01:44:48 +08:00
|
|
|
skip_all='skipping test, git built without http support'
|
2009-02-25 16:32:09 +08:00
|
|
|
test_done
|
|
|
|
fi
|
|
|
|
|
|
|
|
LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
|
2011-10-18 03:55:47 +08:00
|
|
|
. "$TEST_DIRECTORY"/lib-httpd.sh
|
2009-02-25 16:32:09 +08:00
|
|
|
start_httpd
|
|
|
|
|
|
|
|
test_expect_success 'setup repository' '
|
|
|
|
echo content >file &&
|
|
|
|
git add file &&
|
|
|
|
git commit -m one
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'create http-accessible bare repository' '
|
|
|
|
mkdir "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
|
|
|
git --bare init &&
|
|
|
|
echo "exec git update-server-info" >hooks/post-update &&
|
|
|
|
chmod +x hooks/post-update
|
|
|
|
) &&
|
|
|
|
git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
|
|
|
git push public master:master
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'clone http repository' '
|
2010-11-25 16:21:03 +08:00
|
|
|
git clone $HTTPD_URL/dumb/repo.git clone-tmpl &&
|
|
|
|
cp -R clone-tmpl clone &&
|
2009-02-25 16:32:09 +08:00
|
|
|
test_cmp file clone/file
|
|
|
|
'
|
|
|
|
|
2011-07-18 15:49:12 +08:00
|
|
|
test_expect_success 'create password-protected repository' '
|
2010-11-14 09:51:14 +08:00
|
|
|
mkdir "$HTTPD_DOCUMENT_ROOT_PATH/auth/" &&
|
2011-07-18 15:49:12 +08:00
|
|
|
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
|
|
|
|
"$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git"
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'setup askpass helpers' '
|
|
|
|
cat >askpass <<-EOF &&
|
|
|
|
#!/bin/sh
|
|
|
|
echo >>"$PWD/askpass-query" "askpass: \$*" &&
|
|
|
|
cat "$PWD/askpass-response"
|
|
|
|
EOF
|
|
|
|
chmod +x askpass &&
|
|
|
|
GIT_ASKPASS="$PWD/askpass" &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:21 +08:00
|
|
|
export GIT_ASKPASS
|
2011-07-18 15:49:12 +08:00
|
|
|
'
|
|
|
|
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:21 +08:00
|
|
|
expect_askpass() {
|
credential: make relevance of http path configurable
When parsing a URL into a credential struct, we carefully
record each part of the URL, including the path on the
remote host, and use the result as part of the credential
context.
This had two practical implications:
1. Credential helpers which store a credential for later
access are likely to use the "path" portion as part of
the storage key. That means that a request to
https://example.com/foo.git
would not use the same credential that was stored in an
earlier request for:
https://example.com/bar.git
2. The prompt shown to the user includes all relevant
context, including the path.
In most cases, however, users will have a single password
per host. The behavior in (1) will be inconvenient, and the
prompt in (2) will be overly long.
This patch introduces a config option to toggle the
relevance of http paths. When turned on, we use the path as
before. When turned off, we drop the path component from the
context: helpers don't see it, and it does not appear in the
prompt.
This is nothing you couldn't do with a clever credential
helper at the start of your stack, like:
[credential "http://"]
helper = "!f() { grep -v ^path= ; }; f"
helper = your_real_helper
But doing this:
[credential]
useHttpPath = false
is way easier and more readable. Furthermore, since most
users will want the "off" behavior, that is the new default.
Users who want it "on" can set the variable (either for all
credentials, or just for a subset using
credential.*.useHttpPath).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:34 +08:00
|
|
|
dest=$HTTPD_DEST
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:21 +08:00
|
|
|
{
|
|
|
|
case "$1" in
|
|
|
|
none)
|
|
|
|
;;
|
|
|
|
pass)
|
|
|
|
echo "askpass: Password for 'http://$2@$dest': "
|
|
|
|
;;
|
|
|
|
both)
|
|
|
|
echo "askpass: Username for 'http://$dest': "
|
|
|
|
echo "askpass: Password for 'http://$2@$dest': "
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
false
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
} >askpass-expect &&
|
|
|
|
test_cmp askpass-expect askpass-query
|
|
|
|
}
|
|
|
|
|
2011-07-18 15:49:12 +08:00
|
|
|
test_expect_success 'cloning password-protected repository can fail' '
|
|
|
|
>askpass-query &&
|
|
|
|
echo wrong >askpass-response &&
|
|
|
|
test_must_fail git clone "$HTTPD_URL/auth/repo.git" clone-auth-fail &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:21 +08:00
|
|
|
expect_askpass both wrong
|
2011-07-18 15:49:12 +08:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'http auth can use user/pass in URL' '
|
|
|
|
>askpass-query &&
|
2011-12-10 18:30:10 +08:00
|
|
|
echo wrong >askpass-response &&
|
2011-07-18 15:49:12 +08:00
|
|
|
git clone "$HTTPD_URL_USER_PASS/auth/repo.git" clone-auth-none &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:21 +08:00
|
|
|
expect_askpass none
|
2011-07-18 15:49:12 +08:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'http auth can use just user in URL' '
|
|
|
|
>askpass-query &&
|
|
|
|
echo user@host >askpass-response &&
|
|
|
|
git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-pass &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:21 +08:00
|
|
|
expect_askpass pass user@host
|
2011-07-18 15:49:12 +08:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'http auth can request both user and pass' '
|
|
|
|
>askpass-query &&
|
|
|
|
echo user@host >askpass-response &&
|
|
|
|
git clone "$HTTPD_URL/auth/repo.git" clone-auth-both &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 18:31:21 +08:00
|
|
|
expect_askpass both user@host
|
2010-11-14 09:51:14 +08:00
|
|
|
'
|
|
|
|
|
2011-12-10 18:31:24 +08:00
|
|
|
test_expect_success 'http auth respects credential helper config' '
|
|
|
|
test_config_global credential.helper "!f() {
|
|
|
|
cat >/dev/null
|
|
|
|
echo username=user@host
|
|
|
|
echo password=user@host
|
|
|
|
}; f" &&
|
|
|
|
>askpass-query &&
|
|
|
|
echo wrong >askpass-response &&
|
|
|
|
git clone "$HTTPD_URL/auth/repo.git" clone-auth-helper &&
|
|
|
|
expect_askpass none
|
|
|
|
'
|
|
|
|
|
2011-12-10 18:31:30 +08:00
|
|
|
test_expect_success 'http auth can get username from config' '
|
|
|
|
test_config_global "credential.$HTTPD_URL.username" user@host &&
|
|
|
|
>askpass-query &&
|
|
|
|
echo user@host >askpass-response &&
|
|
|
|
git clone "$HTTPD_URL/auth/repo.git" clone-auth-user &&
|
|
|
|
expect_askpass pass user@host
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'configured username does not override URL' '
|
|
|
|
test_config_global "credential.$HTTPD_URL.username" wrong &&
|
|
|
|
>askpass-query &&
|
|
|
|
echo user@host >askpass-response &&
|
|
|
|
git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-user2 &&
|
|
|
|
expect_askpass pass user@host
|
|
|
|
'
|
|
|
|
|
2009-02-25 16:32:09 +08:00
|
|
|
test_expect_success 'fetch changes via http' '
|
|
|
|
echo content >>file &&
|
|
|
|
git commit -a -m two &&
|
2010-11-25 16:21:02 +08:00
|
|
|
git push public &&
|
2009-02-25 16:32:09 +08:00
|
|
|
(cd clone && git pull) &&
|
|
|
|
test_cmp file clone/file
|
|
|
|
'
|
|
|
|
|
2010-11-25 16:21:03 +08:00
|
|
|
test_expect_success 'fetch changes via manual http-fetch' '
|
|
|
|
cp -R clone-tmpl clone2 &&
|
|
|
|
|
|
|
|
HEAD=$(git rev-parse --verify HEAD) &&
|
|
|
|
(cd clone2 &&
|
|
|
|
git http-fetch -a -w heads/master-new $HEAD $(git config remote.origin.url) &&
|
|
|
|
git checkout master-new &&
|
|
|
|
test $HEAD = $(git rev-parse --verify HEAD)) &&
|
|
|
|
test_cmp file clone2/file
|
|
|
|
'
|
|
|
|
|
2009-02-28 03:10:06 +08:00
|
|
|
test_expect_success 'http remote detects correct HEAD' '
|
|
|
|
git push public master:other &&
|
|
|
|
(cd clone &&
|
|
|
|
git remote set-head origin -d &&
|
|
|
|
git remote set-head origin -a &&
|
|
|
|
git symbolic-ref refs/remotes/origin/HEAD > output &&
|
|
|
|
echo refs/remotes/origin/master > expect &&
|
|
|
|
test_cmp expect output
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2009-06-06 16:43:32 +08:00
|
|
|
test_expect_success 'fetch packed objects' '
|
|
|
|
cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
|
2010-04-18 04:07:35 +08:00
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
|
2012-01-04 23:55:34 +08:00
|
|
|
git --bare repack -a -d
|
2010-04-18 04:07:35 +08:00
|
|
|
) &&
|
2009-10-31 08:47:46 +08:00
|
|
|
git clone $HTTPD_URL/dumb/repo_pack.git
|
2009-06-06 16:43:32 +08:00
|
|
|
'
|
|
|
|
|
2010-04-19 22:23:09 +08:00
|
|
|
test_expect_success 'fetch notices corrupt pack' '
|
|
|
|
cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
|
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
|
|
|
|
p=`ls objects/pack/pack-*.pack` &&
|
|
|
|
chmod u+w $p &&
|
|
|
|
printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
|
|
|
|
) &&
|
|
|
|
mkdir repo_bad1.git &&
|
|
|
|
(cd repo_bad1.git &&
|
|
|
|
git --bare init &&
|
|
|
|
test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad1.git &&
|
|
|
|
test 0 = `ls objects/pack/pack-*.pack | wc -l`
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2010-04-19 22:23:10 +08:00
|
|
|
test_expect_success 'fetch notices corrupt idx' '
|
|
|
|
cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
|
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
|
|
|
|
p=`ls objects/pack/pack-*.idx` &&
|
|
|
|
chmod u+w $p &&
|
|
|
|
printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
|
|
|
|
) &&
|
|
|
|
mkdir repo_bad2.git &&
|
|
|
|
(cd repo_bad2.git &&
|
|
|
|
git --bare init &&
|
|
|
|
test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad2.git &&
|
|
|
|
test 0 = `ls objects/pack | wc -l`
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2009-10-31 08:47:47 +08:00
|
|
|
test_expect_success 'did not use upload-pack service' '
|
|
|
|
grep '/git-upload-pack' <"$HTTPD_ROOT_PATH"/access.log >act
|
|
|
|
: >exp
|
|
|
|
test_cmp exp act
|
|
|
|
'
|
|
|
|
|
2009-02-25 16:32:09 +08:00
|
|
|
stop_httpd
|
|
|
|
test_done
|