Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
csppfetch
Manage
Activity
Members
Labels
Plan
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Terraform modules
Analyze
Contributor analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
cspp_geo
csppfetch
Commits
ecd617b7
Commit
ecd617b7
authored
Jul 23, 2021
by
Alan De Smet
Browse files
Options
Downloads
Patches
Plain Diff
ExclusiveLockFile now has tests
parent
cf57a3a7
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
csppfetch/exclusivelockfile.py
+3
-0
3 additions, 0 deletions
csppfetch/exclusivelockfile.py
test-csppfetch.py
+82
-114
82 additions, 114 deletions
test-csppfetch.py
with
85 additions
and
114 deletions
csppfetch/exclusivelockfile.py
+
3
−
0
View file @
ecd617b7
...
@@ -110,6 +110,9 @@ class ExclusiveLockFile:
...
@@ -110,6 +110,9 @@ class ExclusiveLockFile:
def
__exit__
(
self
,
type
,
value
,
traceback
):
def
__exit__
(
self
,
type
,
value
,
traceback
):
self
.
unlock
()
self
.
unlock
()
def
__del__
(
self
):
self
.
file
.
close
()
def
samefile
(
f1
,
f2
):
def
samefile
(
f1
,
f2
):
"""
Do do file objects correspond to the same file on disk?
"""
Do do file objects correspond to the same file on disk?
...
...
...
...
This diff is collapsed.
Click to expand it.
test-csppfetch.py
+
82
−
114
View file @
ecd617b7
#! /usr/bin/python3
#! /usr/bin/python3
import
csppfetch
import
csppfetch
import
csppfetch.exclusivelockfile
import
os
import
os
import
unittest
import
unittest
...
@@ -62,14 +63,6 @@ ELFT_MSG_WAITING = "waiting for lock"
...
@@ -62,14 +63,6 @@ ELFT_MSG_WAITING = "waiting for lock"
ELFT_MSG_LOCKED
=
"
claimed lock, waiting on pipe
"
ELFT_MSG_LOCKED
=
"
claimed lock, waiting on pipe
"
ELFT_MSG_UNLOCKED
=
"
released lock
"
ELFT_MSG_UNLOCKED
=
"
released lock
"
ELFT_MSG_DONE
=
"
exiting
"
ELFT_MSG_DONE
=
"
exiting
"
def
ELFT_lock_sleep_exit
(
title
,
file
,
pipe
,
queue
):
queue
.
put
(
f
"
{
title
}
{
ELFT_MSG_WAITING
}
"
)
from
csppfetch.exclusivelockfile
import
ExclusiveLockFile
import
time
with
ExclusiveLockFile
(
file
):
queue
.
put
(
f
"
{
title
}
{
ELFT_MSG_LOCKED
}
"
)
pipe
.
recv
()
queue
.
put
(
f
"
{
title
}
{
ELFT_MSG_UNLOCKED
}
"
)
def
ELFT_lock_proc
(
title
,
file
,
qresults
,
qcommands
):
def
ELFT_lock_proc
(
title
,
file
,
qresults
,
qcommands
):
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_WAITING
}
"
)
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_WAITING
}
"
)
...
@@ -79,8 +72,9 @@ def ELFT_lock_proc(title, file, qresults, qcommands):
...
@@ -79,8 +72,9 @@ def ELFT_lock_proc(title, file, qresults, qcommands):
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_LOCKED
}
"
)
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_LOCKED
}
"
)
cmd
=
qcommands
.
get
()
cmd
=
qcommands
.
get
()
if
cmd
!=
"
unlock
"
:
if
cmd
!=
"
unlock
"
:
qresults
.
put
(
f
"
{
title
}
received
{
cmd
}
expected unlock
"
)
msg
=
f
"
{
title
}
received
'
{
cmd
}
'
but expected
'
unlock
'"
return
1
qresults
.
put
(
msg
)
raise
Exception
(
msg
)
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_UNLOCKED
}
"
)
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_UNLOCKED
}
"
)
cmd
=
qcommands
.
get
()
cmd
=
qcommands
.
get
()
if
cmd
!=
"
done
"
:
if
cmd
!=
"
done
"
:
...
@@ -88,15 +82,37 @@ def ELFT_lock_proc(title, file, qresults, qcommands):
...
@@ -88,15 +82,37 @@ def ELFT_lock_proc(title, file, qresults, qcommands):
return
1
return
1
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_DONE
}
"
)
qresults
.
put
(
f
"
{
title
}
{
ELFT_MSG_DONE
}
"
)
class
LockProcess
:
def
__init__
(
self
,
name
,
lockfile
,
process
,
qresults
,
qcommands
):
self
.
name
=
name
self
.
lockfile
=
lockfile
self
.
process
=
process
self
.
qresults
=
qresults
self
.
qcommands
=
qcommands
self
.
running
=
False
def
start
(
self
):
if
self
.
running
:
raise
RuntimeError
(
"
trying to start() an already running process
"
)
self
.
process
.
start
()
self
.
running
=
True
def
terminate
(
self
):
if
self
.
running
:
self
.
process
.
terminate
()
self
.
running
=
False
def
get
(
self
):
return
self
.
qresults
.
get
()
def
put
(
self
,
command
):
return
self
.
qcommands
.
put
(
command
)
def
is_quiet
(
self
):
return
self
.
qresults
.
empty
()
class
_
ExclusiveLockFileTests
(
DTestCase
):
class
ExclusiveLockFileTests
(
DTestCase
):
def
Xcreate_lock_process
(
self
,
name
,
lockfile
):
from
multiprocessing
import
Process
,
Pipe
parent_pipe
,
child_pipe
=
Pipe
()
p
=
Process
(
target
=
ELFT_lock_sleep_exit
,
args
=
[
name
,
lockfile
,
child_pipe
])
return
(
p
,
parent_pipe
)
def
create_lock_process
(
self
,
name
,
lockfile
):
def
create_lock_process
(
self
,
name
,
lockfile
):
from
multiprocessing
import
Process
,
Queue
from
multiprocessing
import
Process
,
Queue
...
@@ -104,111 +120,63 @@ class _ExclusiveLockFileTests(DTestCase):
...
@@ -104,111 +120,63 @@ class _ExclusiveLockFileTests(DTestCase):
qcommands
=
Queue
()
qcommands
=
Queue
()
p
=
Process
(
target
=
ELFT_lock_proc
,
p
=
Process
(
target
=
ELFT_lock_proc
,
args
=
[
name
,
lockfile
,
qresults
,
qcommands
])
args
=
[
name
,
lockfile
,
qresults
,
qcommands
])
return
(
p
,
qresults
,
qcommands
)
return
LockProcess
(
name
,
lockfile
,
p
,
qresults
,
qcommands
)
def
Xtest_exclusivelockfile
(
self
):
from
tempfile
import
TemporaryDirectory
from
multiprocessing
import
Queue
# Testing multi-process locking code is awful.
with
TemporaryDirectory
()
as
dir
:
p1
,
p2
,
p3
=
[
None
]
*
3
try
:
queue
=
Queue
()
lockfile
=
dir
+
"
/lock
"
p1
,
p1_pipe
=
self
.
create_lock_process
(
"
p1
"
,
lockfile
,
queue
)
p2
,
p2_pipe
=
self
.
create_lock_process
(
"
p2
"
,
lockfile
,
queue
)
p3
,
p3_pipe
=
self
.
create_lock_process
(
"
p3
"
,
lockfile
,
queue
)
p1
.
start
()
self
.
assertEqual
(
queue
.
get
(),
f
"
p1
{
ELFT_MSG_WAITING
}
"
)
self
.
assertEqual
(
queue
.
get
(),
f
"
p1
{
ELFT_MSG_LOCKED
}
"
)
self
.
assertTrue
(
queue
.
empty
())
p2
.
start
()
self
.
assertEqual
(
queue
.
get
(),
f
"
p2
{
ELFT_MSG_WAITING
}
"
)
self
.
assertTrue
(
queue
.
empty
())
p1_pipe
.
send
(
"
go
"
)
more
=
sorted
([
queue
.
get
(),
queue
.
get
()])
self
.
assertEqual
(
more
,
[
f
"
p1
{
ELFT_MSG_UNLOCKED
}
"
,
f
"
p2
{
ELFT_MSG_LOCKED
}
"
])
p1
.
join
()
p1
=
None
# When we get "p1 {ELFT_MSG_UNLOCKED}", the lockfile should be unlinked
# What happened with p3 shows up?
p3
.
start
()
self
.
assertEqual
(
queue
.
get
(),
f
"
p3
{
ELFT_MSG_WAITING
}
"
)
#print("1",queue.get())
#print("2",queue.get())
#print("3",queue.get())
self
.
assertTrue
(
queue
.
empty
())
p2_pipe
.
send
(
"
go
"
)
more
=
sorted
([
queue
.
get
(),
queue
.
get
()])
self
.
assertEqual
(
more
,
[
f
"
p2
{
ELFT_MSG_UNLOCKED
}
"
,
f
"
p3
{
ELFT_MSG_LOCKED
}
"
])
p2
.
join
()
p2
=
None
p3_pipe
.
send
(
"
go
"
)
self
.
assertEqual
(
queue
.
get
(),
f
"
p3
{
ELFT_MSG_UNLOCKED
}
"
)
p3
.
join
()
p3
=
None
self
.
assertTrue
(
queue
.
empty
())
finally
:
if
p1
is
not
None
:
p1
.
terminate
()
if
p2
is
not
None
:
p2
.
terminate
()
if
p3
is
not
None
:
p3
.
terminate
()
def
test_exclusivelockfile
(
self
):
def
test_exclusivelockfile
(
self
):
from
tempfile
import
TemporaryDirectory
from
tempfile
import
TemporaryDirectory
# Trying to deterministically test non-deterministic code is awful
# Trying to deterministically test non-deterministic code is awful
with
TemporaryDirectory
()
as
dir
:
with
TemporaryDirectory
()
as
dir
:
p1
,
p2
,
p3
=
[
None
]
*
3
p
=
[]
lockfile
=
dir
+
"
/lock
"
open
(
lockfile
,
"
x
"
).
close
()
try
:
try
:
lockfile
=
dir
+
"
/lock
"
lockfile
=
dir
+
"
/lock
"
p1
,
p1_res
,
p1_cmd
=
self
.
create_lock_process
(
"
p1
"
,
lockfile
)
p
=
[
self
.
create_lock_process
(
f
"
p
{
i
}
"
,
lockfile
)
for
i
in
range
(
3
)]
p2
,
p2_res
,
p2_cmd
=
self
.
create_lock_process
(
"
p2
"
,
lockfile
)
p3
,
p3_res
,
p3_cmd
=
self
.
create_lock_process
(
"
p3
"
,
lockfile
)
p
[
0
].
start
()
p1
.
start
()
self
.
assertEqual
(
p
[
0
].
get
(),
f
"
p0
{
ELFT_MSG_WAITING
}
"
)
self
.
assertEqual
(
p1_res
.
get
(),
f
"
p1
{
ELFT_MSG_WAITING
}
"
)
self
.
assertEqual
(
p
[
0
].
get
(),
f
"
p0
{
ELFT_MSG_LOCKED
}
"
)
self
.
assertEqual
(
p1_res
.
get
(),
f
"
p1
{
ELFT_MSG_LOCKED
}
"
)
self
.
assertTrue
(
p
[
0
].
is_quiet
())
self
.
assertTrue
(
p1_res
.
empty
())
p
[
1
].
start
()
p2
.
start
()
self
.
assertEqual
(
p
[
1
].
get
(),
f
"
p1
{
ELFT_MSG_WAITING
}
"
)
self
.
assertEqual
(
p2_res
.
get
(),
f
"
p2
{
ELFT_MSG_WAITING
}
"
)
self
.
assertTrue
(
p
[
0
].
is_quiet
())
self
.
assertTrue
(
p2_res
.
empty
())
self
.
assertTrue
(
p
[
1
].
is_quiet
())
self
.
assertTrue
(
p1_res
.
empty
())
p
[
0
].
put
(
"
unlock
"
)
p1_cmd
.
put
(
"
unlock
"
)
self
.
assertEqual
(
p
[
0
].
get
(),
f
"
p0
{
ELFT_MSG_UNLOCKED
}
"
)
self
.
assertEqual
(
p1_res
.
get
(),
f
"
p1
{
ELFT_MSG_UNLOCKED
}
"
)
self
.
assertTrue
(
p
[
0
].
is_quiet
())
self
.
assertEqual
(
p2_res
.
get
(),
f
"
p2
{
ELFT_MSG_LOCKED
}
"
)
self
.
assertEqual
(
p
[
1
].
get
(),
f
"
p1
{
ELFT_MSG_LOCKED
}
"
)
self
.
assertTrue
(
p2_res
.
empty
())
self
.
assertTrue
(
p
[
1
].
is_quiet
())
self
.
assertTrue
(
p1_res
.
empty
())
p
[
0
].
put
(
"
done
"
)
p1_cmd
.
put
(
"
done
"
)
self
.
assertEqual
(
p
[
0
].
get
(),
f
"
p0
{
ELFT_MSG_DONE
}
"
)
self
.
assertEqual
(
p1_res
.
get
(),
f
"
p1
{
ELFT_MSG_DONE
}
"
)
self
.
assertTrue
(
p
[
0
].
is_quiet
())
self
.
assertTrue
(
p2_res
.
empty
())
self
.
assertTrue
(
p
[
1
].
is_quiet
())
self
.
assertTrue
(
p1_res
.
empty
())
p
[
1
].
put
(
"
unlock
"
)
self
.
assertEqual
(
p
[
1
].
get
(),
f
"
p1
{
ELFT_MSG_UNLOCKED
}
"
)
self
.
assertTrue
(
False
)
self
.
assertTrue
(
p
[
1
].
is_quiet
())
p
[
1
].
put
(
"
done
"
)
more
=
sorted
([
queue
.
get
(),
queue
.
get
()])
self
.
assertEqual
(
p
[
1
].
get
(),
f
"
p1
{
ELFT_MSG_DONE
}
"
)
self
.
assertEqual
(
more
,
[
f
"
p1
{
ELFT_MSG_UNLOCKED
}
"
,
f
"
p2
{
ELFT_MSG_LOCKED
}
"
])
self
.
assertTrue
(
p
[
1
].
is_quiet
())
p1
.
join
()
p1
=
None
# The other locks are gone, this should be trivial
# When we get "p1 {ELFT_MSG_UNLOCKED}", the lockfile should be unlinked
p
[
2
].
start
()
# What happened with p3 shows up?
self
.
assertEqual
(
p
[
2
].
get
(),
f
"
p2
{
ELFT_MSG_WAITING
}
"
)
p3
.
start
()
self
.
assertEqual
(
p
[
2
].
get
(),
f
"
p2
{
ELFT_MSG_LOCKED
}
"
)
self
.
assertEqual
(
queue
.
get
(),
f
"
p3
{
ELFT_MSG_WAITING
}
"
)
self
.
assertTrue
(
p
[
2
].
is_quiet
())
#print("1",queue.get())
p
[
2
].
put
(
"
unlock
"
)
#print("2",queue.get())
self
.
assertEqual
(
p
[
2
].
get
(),
f
"
p2
{
ELFT_MSG_UNLOCKED
}
"
)
#print("3",queue.get())
self
.
assertTrue
(
p
[
2
].
is_quiet
())
self
.
assertTrue
(
queue
.
empty
())
p
[
2
].
put
(
"
done
"
)
p2_pipe
.
send
(
"
go
"
)
self
.
assertEqual
(
p
[
2
].
get
(),
f
"
p2
{
ELFT_MSG_DONE
}
"
)
more
=
sorted
([
queue
.
get
(),
queue
.
get
()])
self
.
assertTrue
(
p
[
2
].
is_quiet
())
self
.
assertEqual
(
more
,
[
f
"
p2
{
ELFT_MSG_UNLOCKED
}
"
,
f
"
p3
{
ELFT_MSG_LOCKED
}
"
])
p2
.
join
()
self
.
assertTrue
(
p
[
0
].
is_quiet
())
p2
=
None
self
.
assertTrue
(
p
[
1
].
is_quiet
())
p3_pipe
.
send
(
"
go
"
)
self
.
assertTrue
(
p
[
2
].
is_quiet
())
self
.
assertEqual
(
queue
.
get
(),
f
"
p3
{
ELFT_MSG_UNLOCKED
}
"
)
p3
.
join
()
p3
=
None
self
.
assertTrue
(
queue
.
empty
())
finally
:
finally
:
if
p1
is
not
None
:
p1
.
terminate
()
for
i
in
p
:
if
p2
is
not
None
:
p2
.
terminate
()
i
.
terminate
()
if
p3
is
not
None
:
p3
.
terminate
()
...
...
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
sign in
to comment